Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

prehistory

Bilang mahilig sa retro hardware, minsan akong bumili ng ZX Spectrum+ mula sa isang nagbebenta sa UK. Kasama sa computer mismo, nakatanggap ako ng ilang mga audio cassette na may mga laro (sa orihinal na packaging na may mga tagubilin), pati na rin ang mga programa na naitala sa mga cassette na walang mga espesyal na marka. Nakapagtataka, ang data mula sa 40-taong-gulang na mga cassette ay nababasa nang mabuti at nagawa kong i-download ang halos lahat ng mga laro at programa mula sa kanila.

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Gayunpaman, sa ilang mga cassette nakita ko ang mga pag-record na malinaw na hindi ginawa ng ZX Spectrum computer. Ang mga ito ay ganap na naiiba at, hindi katulad ng mga pag-record mula sa nabanggit na computer, hindi sila nagsimula sa isang maikling BASIC bootloader, na kadalasang naroroon sa mga pag-record ng lahat ng mga programa at laro.

For some time this haunted me - Gusto ko talagang malaman kung ano ang nakatago sa kanila. Kung mababasa mo ang audio signal bilang isang sequence ng mga byte, maaari kang maghanap ng mga character o anumang bagay na nagpapahiwatig ng pinagmulan ng signal. Isang uri ng retro-archaeology.

Ngayon na napunta na ako sa lahat ng paraan at tiningnan ang mga label ng mga cassette mismo, napangiti ako dahil

ang sagot ay nasa harap ng aking mga mata
Sa label ng kaliwang cassette ay ang pangalan ng TRS-80 computer, at sa ibaba lamang ng pangalan ng tagagawa: "Ginawa ng Radio Shack sa USA"

(Kung nais mong panatilihin ang intriga hanggang sa huli, huwag pumunta sa ilalim ng spoiler)

Paghahambing ng mga signal ng audio

Una sa lahat, i-digitize natin ang mga audio recording. Maaari mong pakinggan kung ano ang tunog nito:


At gaya ng dati ang pag-record mula sa ZX Spectrum computer ay tumutunog:


Sa parehong mga kaso, sa simula ng pag-record mayroong isang tinatawag na pilot tone - isang tunog ng parehong dalas (sa unang pag-record ito ay napakaikli <1 segundo, ngunit nakikilala). Ang pilot tone ay nagpapahiwatig sa computer na maghanda upang makatanggap ng data. Bilang isang tuntunin, kinikilala lamang ng bawat computer ang "sariling" pilot tone nito sa pamamagitan ng hugis ng signal at dalas nito.

Kinakailangang sabihin ang tungkol sa hugis ng signal mismo. Halimbawa, sa ZX Spectrum ang hugis nito ay hugis-parihaba:

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Kapag may nakitang pilot tone, ang ZX Spectrum ay nagpapakita ng mga alternating red at blue bar sa border ng screen upang ipahiwatig na ang signal ay nakilala. Nagtatapos ang tono ng piloto synchro pulse, na senyales sa computer na magsimulang tumanggap ng data. Ito ay nailalarawan sa pamamagitan ng isang mas maikling tagal (kumpara sa tono ng piloto at kasunod na data) (tingnan ang figure)

Matapos matanggap ang pulso ng pag-sync, itinatala ng computer ang bawat pagtaas/pagbagsak ng signal, sinusukat ang tagal nito. Kung ang tagal ay mas mababa sa isang tiyak na limitasyon, ang bit 1 ay isinusulat sa memorya, kung hindi ay 0. Ang mga bit ay kinokolekta sa mga byte at ang proseso ay paulit-ulit hanggang sa N bytes ay matanggap. Karaniwang kinukuha ang numerong N mula sa header ng na-download na file. Ang pagkakasunud-sunod ng paglo-load ay ang mga sumusunod:

  1. pilot tone
  2. header (fixed length), naglalaman ng laki ng na-download na data (N), pangalan ng file at uri
  3. pilot tone
  4. ang data mismo

Upang matiyak na ang data ay na-load nang tama, binabasa ng ZX Spectrum ang tinatawag na parity byte (parity byte), na kinakalkula kapag nagse-save ng file sa pamamagitan ng XORing ng lahat ng byte ng nakasulat na data. Kapag nagbabasa ng isang file, kinakalkula ng computer ang parity byte mula sa natanggap na data at, kung ang resulta ay naiiba sa na-save, ipinapakita ang mensahe ng error na "R Tape loading error". Sa mahigpit na pagsasalita, maaaring mailabas ng computer ang mensaheng ito nang mas maaga kung, kapag nagbabasa, hindi nito nakikilala ang isang pulso (napalampas o ang tagal nito ay hindi tumutugma sa ilang mga limitasyon)

Kaya, tingnan natin ngayon kung ano ang hitsura ng hindi kilalang signal:

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Ito ang tono ng piloto. Ang hugis ng signal ay makabuluhang naiiba, ngunit ito ay malinaw na ang signal ay binubuo ng paulit-ulit na maikling pulso ng isang tiyak na dalas. Sa dalas ng sampling na 44100 Hz, ang distansya sa pagitan ng "mga taluktok" ay humigit-kumulang 48 sample (na tumutugma sa dalas ng ~918 Hz). Tandaan natin ang figure na ito.

Tingnan natin ngayon ang fragment ng data:

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Kung susukatin natin ang distansya sa pagitan ng mga indibidwal na pulso, lumalabas na ang distansya sa pagitan ng "mahaba" na mga pulso ay ~48 mga sample pa rin, at sa pagitan ng mga maikli - ~24. Sa unahan ng kaunti, sasabihin ko na sa huli ay lumabas na ang mga "reference" na pulso na may dalas na 918 Hz ay ​​patuloy na sumusunod, mula sa simula hanggang sa dulo ng file. Maaaring ipagpalagay na kapag nagpapadala ng data, kung ang isang karagdagang pulso ay nakatagpo sa pagitan ng mga reference pulse, itinuturing namin ito bilang bit 1, kung hindi man 0.

Paano ang pulso ng pag-sync? Tingnan natin ang simula ng data:

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Ang pilot tone ay nagtatapos at ang data ay magsisimula kaagad. Maya-maya, pagkatapos suriin ang ilang magkakaibang audio recording, natuklasan namin na ang unang byte ng data ay palaging pareho (10100101b, A5h). Maaaring magsimulang magbasa ng data ang computer pagkatapos nitong matanggap ito.

Maaari mo ring bigyang-pansin ang paglilipat ng unang reference pulse kaagad pagkatapos ng huling 1st sa sync byte. Natuklasan ito nang maglaon sa proseso ng pagbuo ng isang programa sa pagkilala ng data, kapag ang data sa simula ng file ay hindi mababasa nang matatag.

Ngayon subukan nating ilarawan ang isang algorithm na magpoproseso ng audio file at maglo-load ng data.

Loading data

Una, tingnan natin ang ilang mga pagpapalagay upang mapanatiling simple ang algorithm:

  1. Isasaalang-alang lamang namin ang mga file sa WAV na format;
  2. Ang audio file ay dapat magsimula sa isang pilot tone at hindi dapat maglaman ng katahimikan sa simula
  3. Ang source file ay dapat may sampling rate na 44100 Hz. Sa kasong ito, ang distansya sa pagitan ng reference pulses ng 48 samples ay natukoy na at hindi namin kailangang kalkulahin ito sa programmatically;
  4. Ang sample na format ay maaaring maging anumang (8/16 bits/floating point) - dahil kapag nagbabasa ay maaari nating i-convert ito sa nais;
  5. Ipinapalagay namin na ang source file ay na-normalize ng amplitude, na dapat patatagin ang resulta;

Ang algorithm sa pagbabasa ay ang mga sumusunod:

  1. Binabasa namin ang file sa memorya, sa parehong oras na nagko-convert ng sample na format sa 8 bits;
  2. Tukuyin ang posisyon ng unang pulso sa data ng audio. Upang gawin ito, kailangan mong kalkulahin ang bilang ng sample na may pinakamataas na amplitude. Para sa pagiging simple, kakalkulahin namin ito nang manu-mano nang isang beses. I-save natin ito sa variable prev_pos;
  3. Magdagdag ng 48 sa posisyon ng huling pulso (pos := prev_pos + 48)
  4. Dahil ang pagtaas ng posisyon ng 48 ay hindi ginagarantiyahan na makakarating tayo sa posisyon ng susunod na reference pulse (mga depekto sa tape, hindi matatag na operasyon ng mekanismo ng tape drive, atbp.), Kailangan nating ayusin ang posisyon ng pos pulse. Upang gawin ito, kumuha ng isang maliit na piraso ng data (pos-8; pos+8) at hanapin ang pinakamataas na halaga ng amplitude dito. Ang posisyon na naaayon sa maximum ay maiimbak sa pos. Narito ang 8 = 48/6 ay isang eksperimento na nakuha na pare-pareho, na ginagarantiyahan na matutukoy namin ang tamang maximum at hindi makakaapekto sa iba pang mga impulses na maaaring nasa malapit. Sa napakasamang mga kaso, kapag ang distansya sa pagitan ng mga pulso ay mas mababa sa o mas malaki kaysa sa 48, maaari mong ipatupad ang isang sapilitang paghahanap para sa isang pulso, ngunit sa loob ng saklaw ng artikulo ay hindi ko ilalarawan ito sa algorithm;
  5. Sa nakaraang hakbang, kakailanganin din na suriin na ang reference pulse ay natagpuan sa lahat. Iyon ay, kung hahanapin mo lang ang maximum, hindi nito ginagarantiyahan na ang salpok ay naroroon sa segment na ito. Sa aking pinakabagong pagpapatupad ng programa sa pagbabasa, sinusuri ko ang pagkakaiba sa pagitan ng maximum at minimum na mga halaga ng amplitude sa isang segment, at kung lumampas ito sa isang tiyak na limitasyon, binibilang ko ang pagkakaroon ng isang salpok. Ang tanong ay kung ano ang gagawin kung hindi natagpuan ang reference pulse. Mayroong 2 opsyon: maaaring natapos na ang data at sumunod ang katahimikan, o dapat itong ituring na error sa pagbabasa. Gayunpaman, aalisin namin ito upang gawing simple ang algorithm;
  6. Sa susunod na hakbang, kailangan nating matukoy ang pagkakaroon ng isang pulso ng data (bit 0 o 1), para dito kinukuha natin ang gitna ng segment (prev_pos;pos) middle_pos na katumbas ng middle_pos := (prev_pos+pos)/2 at sa ilang kapitbahayan ng middle_pos sa segment (middle_pos-8;middle_pos +8) kalkulahin natin ang maximum at minimum amplitude. Kung ang pagkakaiba sa pagitan ng mga ito ay higit sa 10, isinusulat namin ang bit 1 sa resulta, kung hindi man 0. 10 ay isang pare-pareho na nakuha sa eksperimento;
  7. I-save ang kasalukuyang posisyon sa prev_pos (prev_pos := pos)
  8. Ulitin simula sa hakbang 3 hanggang mabasa namin ang buong file;
  9. Ang resultang bit array ay dapat na i-save bilang isang set ng mga byte. Dahil hindi namin isinasaalang-alang ang sync byte kapag nagbabasa, ang bilang ng mga bit ay maaaring hindi maramihang 8, at ang kinakailangang bit offset ay hindi rin alam. Sa unang pagpapatupad ng algorithm, hindi ko alam ang tungkol sa pagkakaroon ng sync byte at samakatuwid ay nag-save lamang ng 8 mga file na may iba't ibang bilang ng mga offset bit. Ang isa sa mga ito ay naglalaman ng tamang data. Sa panghuling algorithm, inaalis ko lang ang lahat ng mga bit hanggang sa A5h, na nagpapahintulot sa akin na agad na makuha ang tamang output file

Algorithm sa Ruby, para sa mga interesado
Pinili ko si Ruby bilang wika para sa pagsulat ng programa, dahil... Pino-program ko ito sa halos lahat ng oras. Ang pagpipilian ay hindi mataas ang pagganap, ngunit ang gawain ng paggawa ng bilis ng pagbabasa nang mabilis hangga't maaari ay hindi katumbas ng halaga.

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

Resulta

Ang pagkakaroon ng pagsubok ng ilang mga variant ng algorithm at constants, ako ay mapalad na makakuha ng isang bagay na lubhang kawili-wili:

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Kaya, sa paghusga sa mga string ng character, mayroon kaming isang programa para sa paglalagay ng mga graph. Gayunpaman, walang mga keyword sa teksto ng programa. Ang lahat ng mga keyword ay naka-encode bilang mga byte (bawat halaga > 80h). Ngayon kailangan nating malaman kung aling computer mula sa 80s ang makakapag-save ng mga programa sa format na ito.

Sa katunayan, ito ay halos kapareho sa isang BASIC na programa. Ang ZX Spectrum na computer ay nag-iimbak ng mga programa sa humigit-kumulang sa parehong format sa memorya at nagse-save ng mga programa sa tape. Kung sakali, sinuri ko ang mga keyword laban mesa. Gayunpaman, ang resulta ay malinaw na negatibo.

Sinuri ko rin ang BASIC na mga keyword ng sikat na Atari, Commodore 64 at ilang iba pang mga computer noong panahong iyon, kung saan nakahanap ako ng dokumentasyon, ngunit walang tagumpay - ang aking kaalaman sa mga uri ng mga retro na computer ay naging hindi masyadong malawak.

Pagkatapos ay nagpasya akong pumunta ang listahan, at pagkatapos ay nahulog ang aking tingin sa pangalan ng tagagawa ng Radio Shack at ang TRS-80 na computer. Ito ang mga pangalan na nakasulat sa mga label ng mga cassette na nakalatag sa aking mesa! Hindi ko alam ang mga pangalang ito noon at hindi pamilyar sa TRS-80 na computer, kaya tila sa akin na ang Radio Shack ay isang tagagawa ng audio cassette tulad ng BASF, Sony o TDK, at ang TRS-80 ang oras ng pag-playback. Bakit hindi?

Computer Tandy/Radio Shack TRS-80

Malamang na ang audio recording na pinag-uusapan, na ibinigay ko bilang isang halimbawa sa simula ng artikulo, ay ginawa sa isang computer na tulad nito:

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Ito ay lumabas na ang computer na ito at ang mga uri nito (Model I/Model III/Model IV, atbp.) ay napakapopular sa isang pagkakataon (siyempre, hindi sa Russia). Kapansin-pansin na ang ginamit nilang processor ay Z80 din. Para sa computer na ito maaari mong mahanap sa Internet maraming impormasyon. Noong dekada 80, ipinamahagi ang impormasyon sa computer sa mga magasin. Sa ngayon ay may ilan mga emulator mga computer para sa iba't ibang platform.

Nagdownload ako ng emulator trs80gp at sa unang pagkakataon nakita ko kung paano gumagana ang computer na ito. Siyempre, hindi sinusuportahan ng computer ang output ng kulay; ang resolution ng screen ay 128x48 pixels lamang, ngunit mayroong maraming mga extension at pagbabago na maaaring tumaas ang resolution ng screen. Marami ring mga opsyon para sa mga operating system para sa computer na ito at mga opsyon para sa pagpapatupad ng BASIC na wika (na, hindi katulad ng ZX Spectrum, sa ilang mga modelo ay hindi man lang "na-flash" sa ROM at anumang opsyon ay maaaring i-load mula sa isang floppy disk, tulad ng ang OS mismo)

Nakahanap din ako utility upang i-convert ang mga pag-record ng audio sa format na CAS, na sinusuportahan ng mga emulator, ngunit sa ilang kadahilanan ay hindi posible na basahin ang mga pag-record mula sa aking mga cassette gamit ang mga ito.

Nang malaman ang format ng CAS file (na naging isang bit-by-bit na kopya lamang ng data mula sa tape na nasa kamay ko na, maliban sa header na may presensya ng isang sync byte), gumawa ako ng ilang mga pagbabago sa aking programa at nakapag-output ng gumaganang CAS file na nagtrabaho sa emulator (TRS-80 Model III):

Paano ko nakuhang muli ang data sa hindi kilalang format mula sa magnetic tape

Idinisenyo ko ang pinakabagong bersyon ng utility ng conversion na may awtomatikong pagtukoy ng unang pulso at ang distansya sa pagitan ng mga reference pulse bilang isang pakete ng GEM, ang source code ay available sa Github.

Konklusyon

Ang landas na aming tinahak ay naging isang kamangha-manghang paglalakbay sa nakaraan, at ako ay natutuwa na sa huli ay natagpuan ko ang sagot. Sa iba pang mga bagay, ako:

  • Naisip ko ang format para sa pag-save ng data sa ZX Spectrum at pinag-aralan ang built-in na ROM routines para sa pag-save/pagbasa ng data mula sa mga audio cassette
  • Nakilala ko ang TRS-80 na computer at ang mga uri nito, pinag-aralan ang operating system, tumingin sa mga sample na programa at kahit na nagkaroon ng pagkakataon na mag-debug sa mga code ng makina (pagkatapos ng lahat, pamilyar sa akin ang lahat ng Z80 mnemonics)
  • Sumulat ng isang ganap na utility para sa pag-convert ng mga audio recording sa CAS na format, na maaaring magbasa ng data na hindi kinikilala ng "opisyal" na utility

Pinagmulan: www.habr.com

Magdagdag ng komento