Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

historiaurrea

Retro hardwarearen maitalea izaki, behin ZX Spectrum+ bat erosi nuen Erresuma Batuko saltzaile bati. Ordenagailuarekin batera sartuta, hainbat audio-kasete jaso nituen jokoekin (jatorrizko ontzian argibideekin), baita marka berezirik gabeko kaseteetan grabatutako programak ere. Harrigarria bada ere, 40 urteko kaseteetako datuak ondo irakurtzen ziren eta haietatik ia joko eta programa guztiak deskargatu ahal izan nituen.

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Hala ere, kasete batzuetan ZX Spectrum ordenagailuak egin gabeko grabazioak aurkitu ditut. Soinu guztiz ezberdina zuten eta, aipatutako ordenagailuko grabazioek ez bezala, ez ziren BASIC abiarazle labur batekin hasi, programa eta joko guztien grabazioetan egon ohi dena.

Aspaldi batez, honek hondatu ninduen - benetan jakin nahi nuen haietan zer zegoen ezkutatuta. Audio-seinalea byte-sekuentzia gisa irakurriko bazenu, karaktereak edo seinalearen jatorria adierazten duen edozer bilatu dezakezu. Retro-arkeologia moduko bat.

Orain bide osoa egin eta kaseten etiketak beraiek begiratuta, irribarre egiten dut zeren eta

erantzuna nire begien aurrean egon zen denbora guztian
Ezkerreko kasetearen etiketan TRS-80 ordenagailuaren izena dago, eta fabrikatzailearen izenaren azpian: "Radio Shack-ek AEBetan fabrikatua"

(Intriga amaierara arte mantendu nahi baduzu, ez sartu spoiler azpian)

Audio-seinaleen alderaketa

Lehenik eta behin, digitaliza ditzagun audio-grabaketak. Nolako soinua entzun dezakezu:


Eta ohi bezala ZX Spectrum ordenagailutik egindako grabaketak soinuak ematen ditu:


Bi kasuetan, grabazioaren hasieran deitzen den bat dago tonu pilotua - Maiztasun bereko soinua (lehenengo grabazioan oso laburra da <1 segundo, baina bereizgarria da). Pilotu-tonuak ordenagailuari seinalea ematen dio datuak jasotzeko prestatzeko. Oro har, ordenagailu bakoitzak bere tonu pilotu "propia" bakarrik ezagutzen du seinalearen formaren eta maiztasunaren arabera.

Seinalearen forma berari buruz zerbait esan beharra dago. Adibidez, ZX Spectrum-en bere forma laukizuzena da:

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Pilotu-tonu bat hautematen denean, ZX Spectrum-ek barra gorriak eta urdinak txandakatu egiten ditu pantailaren ertzean, seinalea ezagutu dela adierazteko. Tonu pilotua amaitzen da pultsu sinkronikoa, ordenagailuari datuak jasotzen hasteko seinalea ematen diona. Iraupen laburragoa da (pilotu tonuarekin eta ondorengo datuekin alderatuta) (ikus irudia)

Sinkronizazio-pultsua jaso ondoren, ordenagailuak seinalearen igoera/jaitsiera bakoitza erregistratzen du, bere iraupena neurtuz. Iraupena muga jakin bat baino txikiagoa bada, 1 bit idazten da memorian, bestela 0. Bitak bytetan biltzen dira eta prozesua errepikatzen da N byte jaso arte. N zenbakia deskargatutako fitxategiaren goiburutik hartu ohi da. Kargatzeko sekuentzia hau da:

  1. tonu pilotua
  2. goiburua (luzera finkoa), deskargatutako datuen tamaina (N), fitxategiaren izena eta mota ditu
  3. tonu pilotua
  4. datuak berak

Datuak behar bezala kargatzen direla ziurtatzeko, ZX Spectrum-ek deitutakoa irakurtzen du parekotasun byte (paritate-byte), fitxategi bat gordetzean kalkulatzen dena idatzitako datuen byte guztiak XOR eginez. Fitxategi bat irakurtzean, ordenagailuak paritate-bytea kalkulatzen du jasotako datuetatik eta, emaitza gordetakoarekin alderatuta, errore-mezua bistaratzen du "R Tape loading error". Zorrotz esanda, ordenagailuak mezu hau lehenago igorri dezake, irakurtzean, pultsurik ezagutzen ez badu (galdutako edo haren iraupena muga batzuekin bat ez badator)

Beraz, ikus dezagun seinale ezezagun bat nolakoa den:

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Hau da tonu pilotua. Seinalearen forma nabarmen desberdina da, baina argi dago seinalea maiztasun jakin bateko pultsu laburrak errepikatzean datza. 44100 Hz-ko laginketa-maiztasunarekin, "tontorren" arteko distantzia gutxi gorabehera 48 lagin da (~ 918 Hz-eko maiztasunari dagokio).Gogora dezagun irudi hau.

Ikus dezagun orain datu zatia:

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Pultsu indibidualen arteko distantzia neurtzen badugu, ikusten da pultsu "luzeen" arteko distantzia ~ 48 lagin dela oraindik, eta laburren artean - ~ 24. Aurrera begira, esango dut azkenean 918 Hz-ko maiztasuneko β€œerreferentzia” pultsuak etengabe jarraitzen dutela, fitxategiaren hasieratik amaierara arte. Onar daiteke datuak igortzerakoan, erreferentzia-pultsuen artean pultsu gehigarri bat aurkitzen bada, 1 bittzat hartuko dugula, bestela 0.

Zer gertatzen da sinkronizazio-pultsuarekin? Ikus ditzagun datuen hasiera:

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Tonu pilotua amaitzen da eta datuak berehala hasten dira. Pixka bat beranduago, hainbat audio-grabaketa aztertu ondoren, datuen lehen bytea beti berdina dela deskubritu ahal izan genuen (10100101b, A5h). Baliteke ordenagailua datuak irakurtzen hastea jaso ondoren.

Lehen erreferentzia-pultsuaren desplazamenduari ere errepara diezaiokezu sinkronizazio bytearen azken 1.aren ondoren. Askoz beranduago aurkitu zen datuak ezagutzeko programa garatzeko prozesuan, fitxategiaren hasierako datuak modu egonkorrean irakurri ezin zirenean.

Orain saia gaitezen audio fitxategi bat prozesatu eta datuak kargatuko dituen algoritmo bat deskribatzen.

Datuak kargatzen

Lehenik eta behin, ikus ditzagun hipotesi batzuk algoritmoa sinplea mantentzeko:

  1. WAV formatuan dauden fitxategiak soilik hartuko ditugu kontuan;
  2. Audio-fitxategiak tonu pilotu batekin hasi behar du eta ez du isiltasunik izan behar hasieran
  3. Iturburu-fitxategiak 44100 Hz-ko laginketa-abiadura izan behar du. Kasu honetan, 48 laginen erreferentzia-pultsuen arteko distantzia zehaztuta dago jada eta ez dugu programatikoki kalkulatu beharrik;
  4. Lagin-formatua edozein izan daiteke (8/16 bit/kopuru mugikorra) - irakurtzerakoan nahi den moduan bihur dezakegulako;
  5. Suposatzen dugu iturburu-fitxategia anplitudearen arabera normalizatuta dagoela, eta horrek emaitza egonkortu beharko luke;

Irakurketa algoritmoa honako hau izango da:

  1. Fitxategia memorian irakurtzen dugu, aldi berean lagin formatua 8 bitera bihurtuz;
  2. Zehaztu lehen pultsuaren posizioa audio-datuetan. Horretarako, laginaren kopurua kalkulatu behar duzu anplitude maximoarekin. Sinpletasuna lortzeko, behin eskuz kalkulatuko dugu. Gorde dezagun prev_pos aldagaian;
  3. Gehitu 48 azken pultsuaren posizioari (pos := prev_pos + 48)
  4. Posizioa 48z handitzeak hurrengo erreferentzia-pultsuaren posiziora iritsiko garela bermatzen ez duenez (zintaren akatsak, zinta gidatzeko mekanismoaren funtzionamendu ezegonkorra, etab.), pos pultsuaren posizioa egokitu behar dugu. Horretarako, hartu datu txiki bat (pos-8;pos+8) eta aurkitu bertan anplitudearen balio maximoa. Gehienezkoari dagokion posizioa pos. Hemen 8 = 48/6 esperimentalki lortutako konstante bat da, eta horrek bermatzen du maximo zuzena zehaztuko dugula eta ez duela eragingo hurbil egon daitezkeen beste bulkadarik. Oso kasu txarretan, pultsuen arteko distantzia 48 baino askoz txikiagoa edo handiagoa denean, pultsu baten bilaketa behartua ezar dezakezu, baina artikuluaren esparruan ez dut hori algoritmoan deskribatuko;
  5. Aurreko urratsean, erreferentziazko pultsu bat aurkitu dela egiaztatu beharko litzateke. Hau da, maximoa besterik gabe bilatzen baduzu, horrek ez du bermatzen bulkada segmentu honetan dagoenik. Irakurketa programaren azken inplementazioan, segmentu batean anplitude maximoaren eta gutxieneko balioen arteko aldea egiaztatzen dut, eta muga jakin bat gainditzen badu, bulkada baten presentzia zenbatzen dut. Galdera ere bada zer egin erreferentzia-pultsua aurkitzen ez bada. 2 aukera daude: edo datuak amaitu eta isiltasuna jarraitzen du, edo hau irakurketa-erroretzat hartu behar da. Hala ere, hori baztertuko dugu algoritmoa sinplifikatzeko;
  6. Hurrengo urratsean, datu-pultsu baten presentzia zehaztu behar dugu (0 edo 1 bit), horretarako segmentuaren erdia hartuko dugu (prev_pos;pos) middle_pos erdiko_pos berdina := (prev_pos+pos)/2 eta segmentuko erdiko_pos-en auzo batzuetan (erdiko_pos-8;erdiko_pos +8) kalkula ditzagun anplitude maximoa eta minimoa. Bien arteko aldea 10 baino handiagoa bada, emaitzan 1 bit idatziko dugu, bestela 0. 10 esperimentalki lortutako konstantea da;
  7. Gorde uneko posizioa prev_pos-en (prev_pos := pos)
  8. Errepikatu 3. urratsetik hasita fitxategi osoa irakurri arte;
  9. Sortutako bit-matrizea byte multzo gisa gorde behar da. Irakurtzerakoan sinkronizazio-bytea kontuan hartu ez dugunez, baliteke bit kopurua ez izatea 8ren multiploa, eta behar den bit-desplazamendua ere ezezaguna da. Algoritmoaren lehen inplementazioan, ez nekien sinkronizazio-bytearen existentziari buruz eta, beraz, 8 fitxategi gorde besterik ez nuen desplazamendu-bit kopuru desberdinekin. Horietako batek datu zuzenak zituen. Azken algoritmoan, A5h-ra arteko bit guztiak kentzen ditut, eta horrek irteerako fitxategi zuzena berehala lortzeko aukera ematen dit

Ruby-n algoritmoa, interesa dutenentzat
Ruby aukeratu nuen programa idazteko hizkuntza gisa, zeren... Gehienetan bertan programatzen dut. Aukera ez da errendimendu handikoa, baina irakurketa abiadura ahalik eta azkarren egiteko lanak ez du merezi.

# Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ 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*")

Emaitza

Algoritmoaren eta konstanteen hainbat aldaera probatu ondoren, zortea izan nuen zerbait oso interesgarria lortzeko:

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Beraz, karaktere-kateak ikusita, grafikoak marrazteko programa dugu. Hala ere, ez dago gako-hitzik programaren testuan. Gako-hitz guztiak byte gisa kodetzen dira (balio bakoitza > 80h). Orain jakin behar dugu 80ko hamarkadako zein ordenagailuk gorde ditzakeen programak formatu honetan.

Izan ere, BASIC programa baten oso antzekoa da. ZX Spectrum ordenagailuak gutxi gorabehera formatu bereko programak gordetzen ditu memorian eta programak zinta batean gordetzen ditu. Badaezpada, gako-hitzak egiaztatu ditut mahaia. Hala ere, emaitza negatiboa izan zen, jakina.

Garai hartako Atari, Commodore 64 eta beste hainbat ordenagailu ezagunen OINARRIZKO gako-hitzak ere egiaztatu nituen, eta horretarako dokumentazioa aurkitu ahal izan nuen, baina arrakastarik gabe - retro ordenagailu motei buruzko nire ezagutza ez zen hain zabala izan.

Orduan joatea erabaki nuen zerrenda, eta orduan nire begirada Radio Shack fabrikatzailearen eta TRS-80 ordenagailuaren izenean erori zen. Hauek dira nire mahai gainean etzanda zeuden kaseteen etiketetan idatzita zeuden izenak! Izen hauek ez nekien aurretik eta ez nekien TRS-80 ordenagailua ezagutzen, beraz, Radio Shack audio-kasete fabrikatzailea zela iruditu zitzaidan, hala nola BASF, Sony edo TDK, eta TRS-80 zen erreprodukzio-denbora. Zergatik ez?

Computer Tandy/Radio Shack TRS-80

Oso litekeena da aipaturiko audio-grabazioa, artikulu hasieran adibide gisa jarri dudana, honelako ordenagailu batean egin izana:

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Konputagailu hau eta bere barietateak (I eredua / III eredua / IV eredua, etab.) oso ezagunak zirela garai batean (noski, ez Errusian). Aipatzekoa da erabili zuten prozesadorea Z80 ere izan zela. Ordenagailu honetarako Interneten aurki dezakezu informazio asko. 80ko hamarkadan informatika informazioa banatu zen aldizkariak. Momentuz hainbat daude emuladoreak plataforma ezberdinetarako ordenagailuak.

Emuladorea deskargatu dut trs80gp eta lehen aldiz ikusi ahal izan nuen nola funtzionatzen zuen ordenagailu honek. Jakina, ordenagailuak ez zuen kolore-irteera onartzen; pantailaren bereizmena 128x48 pixel baino ez zen, baina pantailaren bereizmena handitu zezaketen luzapen eta aldaketa ugari zeuden. Ordenagailu honen sistema eragileetarako aukera asko eta BASIC lengoaia inplementatzeko aukerak ere bazeuden (ZX Spectrum-en ez bezala, eredu batzuetan ez zen ROMan "flash" ere egiten eta edozein aukera kargatu zitekeen diskete batetik, bezalaxe. OS bera)

ere aurkitu dut erabilgarritasuna audio-grabaketak CAS formatura bihurtzeko, emuladoreek onartzen dutena, baina arrazoiren batengatik ezin izan zen nire kaseteetako grabaketak haiek erabiliz irakurri.

CAS fitxategiaren formatua irudikatuta (lehendik eskuan nuen zintaren datuen kopia bat besterik ez zen izan, sinkronizazio byte bat zegoen goiburukoa izan ezik), bat egin nuen. aldaketa gutxi nire programan eta emuladorean funtzionatzen zuen CAS fitxategi bat atera ahal izan nuen (TRS-80 Model III):

Nola berreskuratu nituen datuak zinta magnetikotik formatu ezezagun batean

Bihurketa-erabilgarritasunaren azken bertsioa diseinatu nuen lehenengo pultsuaren eta erreferentzia-pultsuen arteko distantziaren determinazio automatikoarekin GEM pakete gisa, iturburu-kodea eskuragarri dago hemen. Github.

Ondorioa

Egin dugun bidea iraganera bidaia liluragarria izan da, eta pozten naiz azkenean erantzuna aurkitu dudalako. Besteak beste, nik:

  • ZX Spectrum-en datuak gordetzeko formatua asmatu nuen eta audio kaseteetako datuak gordetzeko/irakurtzeko ROM errutinak aztertu nituen.
  • TRS-80 ordenagailua eta bere barietateak ezagutu, sistema eragilea aztertu, lagin-programak aztertu eta makina-kodeetan arazketa egiteko aukera ere izan nuen (azken finean, Z80 mnemoteknia guztiak ezagunak zaizkit)
  • Audio-grabaketak CAS formatura bihurtzeko erabilgarritasun oso bat idatzi du, erabilgarritasun "ofizialak" ezagutzen ez dituen datuak irakur ditzakeena.

Iturria: www.habr.com

Gehitu iruzkin berria