Ako som obnovil dáta v neznámom formáte z magnetickej pásky

pravek

Ako milovník retro hardvéru som si raz kúpil ZX Spectrum+ od predajcu v Spojenom kráľovstve. Súčasťou samotného počítača som dostal niekoľko audiokaziet s hrami (v originálnom balení s návodom), ako aj programy nahrané na kazetách bez špeciálneho označenia. Dáta zo 40-ročných kaziet boli prekvapivo dobre čitateľné a mohol som si z nich stiahnuť takmer všetky hry a programy.

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Na niektorých kazetách som však našiel nahrávky, ktoré zjavne nevyhotovil počítač ZX Spectrum. Zneli úplne inak a na rozdiel od nahrávok zo spomínaného počítača nezačínali krátkym BASIC bootloaderom, ktorý býva prítomný v nahrávkach všetkých programov a hier.

Nejaký čas ma to prenasledovalo - veľmi som chcel zistiť, čo sa v nich skrýva. Ak by ste mohli prečítať zvukový signál ako sekvenciu bajtov, mohli by ste hľadať znaky alebo čokoľvek, čo naznačuje pôvod signálu. Akýsi druh retroarcheológie.

Teraz, keď som prešiel celú cestu a pozrel sa na štítky samotných kaziet, usmievam sa, pretože

odpoveď som mal celý čas priamo pred očami
Na štítku ľavej kazety je názov počítača TRS-80 a hneď pod názvom výrobcu: „Vyrobené spoločnosťou Radio Shack v USA“

(Ak si chcete nechať intrigy až na koniec, nechoďte pod spoiler)

Porovnanie zvukových signálov

V prvom rade digitalizujme zvukové záznamy. Môžete si vypočuť, ako to znie:


A ako obvykle znie záznam z počítača ZX Spectrum:


V oboch prípadoch je na začiatku nahrávky tzv pilotný tón - zvuk rovnakej frekvencie (v prvej nahrávke je veľmi krátky <1 sekunda, ale je rozlíšiteľný). Pilotný tón signalizuje počítaču, aby sa pripravil na príjem údajov. Každý počítač spravidla rozpoznáva iba svoj „vlastný“ pilotný tón podľa tvaru signálu a jeho frekvencie.

K samotnému tvaru signálu je potrebné niečo povedať. Napríklad na ZX Spectrum je jeho tvar obdĺžnikový:

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Keď je detekovaný pilotný tón, ZX Spectrum zobrazuje striedavo červené a modré pruhy na okraji obrazovky, čo znamená, že signál bol rozpoznaný. Pilotný tón končí synchro pulz, ktorý signalizuje počítaču, aby začal prijímať dáta. Vyznačuje sa kratším trvaním (v porovnaní s pilotným tónom a následnými údajmi) (pozri obrázok)

Po prijatí synchronizačného impulzu počítač zaznamená každý vzostup/pokles signálu a meria jeho trvanie. Ak je trvanie kratšie ako určitý limit, bit 1 sa zapíše do pamäte, inak 0. Bity sa zhromažďujú do bajtov a proces sa opakuje, kým sa neprijme N bajtov. Číslo N sa zvyčajne preberá z hlavičky sťahovaného súboru. Postupnosť načítania je nasledovná:

  1. pilotný tón
  2. hlavička (pevná dĺžka), obsahuje veľkosť sťahovaných dát (N), názov súboru a typ
  3. pilotný tón
  4. samotné údaje

Aby ste sa uistili, že dáta sú správne načítané, ZX Spectrum načíta tzv paritný bajt (paritný bajt), ktorý sa vypočíta pri ukladaní súboru XORingom všetkých bajtov zapísaných dát. Pri čítaní súboru počítač z prijatých údajov vypočíta paritný bajt a ak sa výsledok líši od uloženého, ​​zobrazí chybové hlásenie „R Tape loading error“. Presne povedané, počítač môže vydať túto správu skôr, ak pri čítaní nedokáže rozpoznať pulz (zmeškaný alebo jeho trvanie nezodpovedá určitým limitom)

Poďme sa teda pozrieť, ako vyzerá neznámy signál:

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Toto je pilotný tón. Tvar signálu je výrazne odlišný, ale je zrejmé, že signál pozostáva z opakujúcich sa krátkych impulzov určitej frekvencie. Pri vzorkovacej frekvencii 44100 Hz je vzdialenosť medzi „vrcholmi“ približne 48 vzoriek (čo zodpovedá frekvencii ~918 Hz). Tento údaj si zapamätajte.

Pozrime sa teraz na dátový fragment:

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Ak zmeriame vzdialenosť medzi jednotlivými impulzmi, ukáže sa, že vzdialenosť medzi „dlhými“ impulzmi je stále ~ 48 vzoriek a medzi krátkymi - ~ 24. Pri pohľade trochu dopredu poviem, že nakoniec sa ukázalo, že „referenčné“ impulzy s frekvenciou 918 Hz nasledujú nepretržite, od začiatku do konca súboru. Dá sa predpokladať, že pri prenose dát, ak sa medzi referenčnými impulzmi vyskytne dodatočný impulz, považujeme ho za bit 1, inak za 0.

A čo synchronizačný impulz? Pozrime sa na začiatok údajov:

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Pilotný tón sa skončí a dáta začnú okamžite. O niečo neskôr, po analýze niekoľkých rôznych zvukových nahrávok, sme boli schopní zistiť, že prvý bajt údajov je vždy rovnaký (10100101b, A5h). Počítač môže začať čítať údaje po ich prijatí.

Môžete tiež venovať pozornosť posunu prvého referenčného impulzu bezprostredne po poslednom 1. v synchronizačnom byte. Bol objavený oveľa neskôr v procese vývoja programu na rozpoznávanie údajov, keď sa údaje na začiatku súboru nedali stabilne prečítať.

Teraz sa pokúsme opísať algoritmus, ktorý spracuje zvukový súbor a načíta dáta.

Načítavajú sa údaje

Najprv sa pozrime na niekoľko predpokladov, aby bol algoritmus jednoduchý:

  1. Budeme brať do úvahy iba súbory vo formáte WAV;
  2. Zvukový súbor musí začínať pilotným tónom a na začiatku nesmie obsahovať ticho
  3. Zdrojový súbor musí mať vzorkovaciu frekvenciu 44100 Hz. V tomto prípade je vzdialenosť medzi referenčnými impulzmi 48 vzoriek už určená a nemusíme ju počítať programovo;
  4. Formát vzorky môže byť ľubovoľný (8/16 bitov/pohyblivá desatinná čiarka) - keďže pri čítaní ho môžeme previesť na požadovaný;
  5. Predpokladáme, že zdrojový súbor je normalizovaný amplitúdou, čo by malo stabilizovať výsledok;

Algoritmus čítania bude nasledujúci:

  1. Načítame súbor do pamäte a zároveň konvertujeme formát vzorky na 8 bitov;
  2. Určite polohu prvého impulzu v audio dátach. Aby ste to dosiahli, musíte vypočítať počet vzoriek s maximálnou amplitúdou. Pre jednoduchosť to spočítame raz ručne. Uložme to do premennej prev_pos;
  3. Pridajte 48 k pozícii posledného impulzu (pos := prev_pos + 48)
  4. Keďže zvýšenie polohy o 48 nezaručuje, že sa dostaneme do polohy nasledujúceho referenčného impulzu (chyby pásky, nestabilná činnosť mechanizmu pohonu pásky a pod.), musíme upraviť polohu impulzu poz. Ak to chcete urobiť, vezmite malý kus údajov (poz-8;poz+8) a nájdite na ňom maximálnu hodnotu amplitúdy. Pozícia zodpovedajúca maximu bude uložená v poz. Tu 8 = 48/6 je experimentálne získaná konštanta, ktorá zaručuje, že určíme správne maximum a neovplyvníme ostatné impulzy, ktoré môžu byť v blízkosti. Vo veľmi zlých prípadoch, keď je vzdialenosť medzi impulzmi oveľa menšia alebo väčšia ako 48, môžete implementovať nútené vyhľadávanie impulzu, ale v rámci článku to nebudem popisovať v algoritme;
  5. V predchádzajúcom kroku by bolo tiež potrebné skontrolovať, či bol referenčný impulz vôbec nájdený. To znamená, že ak jednoducho hľadáte maximum, nezaručuje to, že impulz je v tomto segmente prítomný. V mojej najnovšej implementácii čítacieho programu kontrolujem rozdiel medzi maximálnymi a minimálnymi hodnotami amplitúdy na segmente a ak prekročí určitú hranicu, počítam prítomnosť impulzu. Otázkou tiež je, čo robiť, ak sa referenčný impulz nenájde. Existujú 2 možnosti: buď sa dáta skončili a nasleduje ticho, alebo by sa to malo považovať za chybu čítania. Pre zjednodušenie algoritmu to však vynecháme;
  6. V ďalšom kroku musíme určiť prítomnosť dátového impulzu (bit 0 alebo 1), na to vezmeme stred segmentu (prev_pos;pos) middle_pos rovný middle_pos := (prev_pos+pos)/2 a v nejakom susedstve middle_pos na segmente (middle_pos-8;middle_pos +8) vypočítajme maximálnu a minimálnu amplitúdu. Ak je rozdiel medzi nimi väčší ako 10, zapíšeme do výsledku bit 1, inak 0. 10 je konštanta získaná experimentálne;
  7. Uložiť aktuálnu pozíciu v prev_pos (prev_pos := pos)
  8. Opakujte od kroku 3, kým neprečítame celý súbor;
  9. Výsledné bitové pole musí byť uložené ako množina bajtov. Keďže sme pri čítaní nebrali do úvahy synchronizačný bajt, počet bitov nemusí byť násobkom 8 a nie je známy ani požadovaný bitový offset. Pri prvej implementácii algoritmu som nevedel o existencii synchronizačného bajtu a preto som jednoducho uložil 8 súborov s rôznym počtom offsetových bitov. Jeden z nich obsahoval správne údaje. V konečnom algoritme jednoducho odstránim všetky bity až do A5h, čo mi umožňuje okamžite získať správny výstupný súbor

Algoritmus v Ruby, pre záujemcov
Ako jazyk na písanie programu som si vybral Ruby, pretože... Väčšinou na ňom programujem. Možnosť nie je vysoko výkonná, ale úloha dosiahnuť čo najrýchlejšiu rýchlosť čítania nestojí za to.

# Используем 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*")

Výsledok

Po vyskúšaní niekoľkých variantov algoritmu a konštánt som mal to šťastie, že som dostal niečo mimoriadne zaujímavé:

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Takže, súdiac podľa reťazcov znakov, máme program na vykresľovanie grafov. V texte programu však nie sú žiadne kľúčové slová. Všetky kľúčové slová sú zakódované ako bajty (každá hodnota > 80h). Teraz musíme zistiť, ktorý počítač z 80. rokov dokázal ukladať programy v tomto formáte.

V skutočnosti je veľmi podobný programu BASIC. Počítač ZX Spectrum ukladá programy v približne rovnakom formáte do pamäte a ukladá programy na pásku. Pre každý prípad som porovnal kľúčové slová tabuľky. Výsledok bol však zjavne negatívny.

Skontroloval som aj základné kľúčové slová populárnych počítačov Atari, Commodore 64 a niekoľkých ďalších vtedajších počítačov, ku ktorým sa mi podarilo nájsť dokumentáciu, no neúspešne - moje znalosti o typoch retro počítačov sa ukázali ako nie také široké.

Potom som sa rozhodol ísť zoznam, a potom môj pohľad padol na meno výrobcu Radio Shack a počítača TRS-80. Toto sú mená, ktoré boli napísané na štítkoch kaziet, ktoré mi ležali na stole! Tieto názvy som predtým nepoznal a nepoznal som počítač TRS-80, takže sa mi zdalo, že Radio Shack bol výrobca audiokaziet ako BASF, Sony alebo TDK a TRS-80 bol čas prehrávania. Prečo nie?

Počítač Tandy/Radio Shack TRS-80

Je veľmi pravdepodobné, že predmetný zvukový záznam, ktorý som uviedol ako príklad na začiatku článku, bol vytvorený na takomto počítači:

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Ukázalo sa, že tento počítač a jeho odrody (Model I/Model III/Model IV atď.) boli svojho času veľmi populárne (samozrejme nie v Rusku). Je pozoruhodné, že procesor, ktorý použili, bol tiež Z80. Pre tento počítač nájdete na internete veľa informácií. V 80. rokoch boli počítačové informácie distribuované v r časopisov. V súčasnosti je ich niekoľko emulátory počítače pre rôzne platformy.

Stiahol som si emulátor trs80gp a prvýkrát som mohol vidieť, ako tento počítač funguje. Počítač samozrejme nepodporoval farebný výstup, rozlíšenie obrazovky bolo len 128x48 pixelov, no bolo veľa rozšírení a úprav, ktoré mohli rozlíšenie obrazovky zvýšiť. Pre tento počítač bolo tiež veľa možností operačných systémov a možností implementácie jazyka BASIC (ktorý sa na rozdiel od ZX Spectra u niektorých modelov ani „neflashoval“ do ROM a ľubovoľnú možnosť bolo možné načítať z diskety, podobne ako napr. samotný OS)

Tiež som našiel užitočnosť previesť audio nahrávky do formátu CAS, ktorý podporujú emulátory, ale z nejakého dôvodu nebolo možné pomocou nich čítať nahrávky z mojich kaziet.

Po zistení formátu súboru CAS (ktorý sa ukázal byť len kópiou údajov z pásky, ktorú som už mal po ruke, s výnimkou hlavičky s prítomnosťou synchronizačného bajtu), som vytvoril niekoľko zmien v mojom programe a bol som schopný vygenerovať pracovný súbor CAS, ktorý fungoval v emulátore (TRS-80 Model III):

Ako som obnovil dáta v neznámom formáte z magnetickej pásky

Najnovšiu verziu konverznej pomôcky s automatickým určením prvého impulzu a vzdialenosti medzi referenčnými impulzmi som navrhol ako balík GEM, zdrojový kód je dostupný na GitHub.

Záver

Cesta, ktorú sme prešli, sa ukázala ako fascinujúca cesta do minulosti a som rád, že som nakoniec našiel odpoveď. Okrem iného som:

  • Prišiel som na formát na ukladanie dát v ZX Spectrum a študoval som vstavané ROM rutiny na ukladanie/čítanie dát z audiokaziet
  • Zoznámil som sa s počítačom TRS-80 a jeho odrodami, študoval som operačný systém, pozrel som si vzorové programy a dokonca som mal možnosť ladiť v strojových kódoch (napokon, všetky mnemotechnické pomôcky Z80 sú mi známe)
  • Napísal plnohodnotný nástroj na konverziu zvukových nahrávok do formátu CAS, ktorý dokáže čítať údaje, ktoré „oficiálny“ nástroj nerozpozná

Zdroj: hab.com

Pridať komentár