Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

parahistorinë

Duke qenë një dashnor i pajisjeve retro, një herë bleva një ZX Spectrum+ nga një shitës në MB. Të përfshira me vetë kompjuterin, mora disa kaseta audio me lojëra (në paketimin origjinal me udhëzime), si dhe programe të regjistruara në kaseta pa shenja të veçanta. Çuditërisht, të dhënat nga kasetat 40-vjeçare ishin të lexueshme mirë dhe unë arrita të shkarkoja pothuajse të gjitha lojërat dhe programet prej tyre.

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Megjithatë, në disa kaseta gjeta regjistrime që nuk ishin bërë qartë nga kompjuteri ZX Spectrum. Ata tingëllonin krejtësisht ndryshe dhe, ndryshe nga regjistrimet nga kompjuteri i përmendur, nuk filluan me një bootloader të shkurtër BASIC, i cili zakonisht është i pranishëm në regjistrimet e të gjitha programeve dhe lojërave.

Për ca kohë kjo më përhumbi - me të vërtetë doja të zbuloja se çfarë fshihej në to. Nëse mund ta lexoni sinjalin audio si një sekuencë bajtësh, mund të kërkoni karaktere ose ndonjë gjë në to që tregon origjinën e sinjalit. Një lloj retro-arkeologjie.

Tani që kam shkuar deri në fund dhe kam parë vetë etiketat e kasetave, buzëqesh sepse

Përgjigja ishte para syve të mi gjatë gjithë kohës
Në etiketën e kasetës së majtë është emri i kompjuterit TRS-80, dhe pak më poshtë emri i prodhuesit: "Prodhuar nga Radio Shack në SHBA"

(Nëse doni ta mbani intrigën deri në fund, mos kaloni nën spoiler)

Krahasimi i sinjaleve audio

Fillimisht, le të dixhitalizojmë regjistrimet audio. Mund të dëgjoni se si tingëllon:


Dhe si zakonisht tingëllon regjistrimi nga kompjuteri ZX Spectrum:


Në të dyja rastet, në fillim të regjistrimit ka një të ashtuquajtur toni pilot - një tingull me të njëjtën frekuencë (në regjistrimin e parë është shumë i shkurtër <1 sekondë, por dallohet). Toni pilot sinjalizon kompjuterin që të përgatitet për të marrë të dhëna. Si rregull, çdo kompjuter njeh vetëm tonin e tij pilot "të vetin" nga forma e sinjalit dhe frekuenca e tij.

Është e nevojshme të thuhet diçka për vetë formën e sinjalit. Për shembull, në spektrin ZX forma e tij është drejtkëndore:

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Kur zbulohet një ton pilot, ZX Spectrum shfaq shirita të alternuar të kuq dhe blu në kufirin e ekranit për të treguar që sinjali është njohur. Toni pilot përfundon puls sinkron, i cili sinjalizon kompjuterin që të fillojë të marrë të dhëna. Karakterizohet nga një kohëzgjatje më e shkurtër (krahasuar me tonin e pilotit dhe të dhënat pasuese) (shih figurën)

Pasi të merret pulsi i sinkronizimit, kompjuteri regjistron çdo rritje/rënie të sinjalit, duke matur kohëzgjatjen e tij. Nëse kohëzgjatja është më e vogël se një kufi i caktuar, biti 1 shkruhet në memorie, përndryshe 0. Bitët mblidhen në bajt dhe procesi përsëritet derisa të merren N bajt. Numri N zakonisht merret nga kreu i skedarit të shkarkuar. Sekuenca e ngarkimit është si më poshtë:

  1. toni pilot
  2. header (gjatësi fikse), përmban madhësinë e të dhënave të shkarkuara (N), emrin dhe llojin e skedarit
  3. toni pilot
  4. vetë të dhënat

Për t'u siguruar që të dhënat janë ngarkuar saktë, ZX Spectrum lexon të ashtuquajturin bajt barazi (bajti i barazisë), i cili llogaritet gjatë ruajtjes së një skedari duke XORuar të gjitha bajtet e të dhënave të shkruara. Kur lexoni një skedar, kompjuteri llogarit bajtin e barazisë nga të dhënat e marra dhe, nëse rezultati ndryshon nga ai i ruajtur, shfaq mesazhin e gabimit "R Tape loading error". Në mënyrë të rreptë, kompjuteri mund ta lëshojë këtë mesazh më herët nëse, gjatë leximit, nuk mund të njohë një puls (të humbur ose kohëzgjatja e tij nuk korrespondon me kufij të caktuar)

Pra, le të shohim tani se si duket një sinjal i panjohur:

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Ky është toni i pilotit. Forma e sinjalit është dukshëm e ndryshme, por është e qartë se sinjali konsiston në përsëritjen e pulseve të shkurtra të një frekuence të caktuar. Në një frekuencë kampionimi prej 44100 Hz, distanca midis "majave" është afërsisht 48 mostra (që korrespondon me një frekuencë prej ~ 918 Hz). Le të kujtojmë këtë shifër.

Le të shohim tani fragmentin e të dhënave:

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Nëse matim distancën midis pulseve individuale, rezulton se distanca midis pulseve "të gjata" është ende ~ 48 mostra, dhe midis atyre të shkurtra - ~ 24. Duke parë pak përpara, do të them se në fund doli që pulset "referenca" me frekuencë 918 Hz ndjekin vazhdimisht, nga fillimi deri në fund të skedarit. Mund të supozohet se gjatë transmetimit të të dhënave, nëse ndeshet një impuls shtesë midis pulseve të referencës, ne e konsiderojmë atë si bit 1, përndryshe 0.

Po në lidhje me pulsin e sinkronizimit? Le të shohim fillimin e të dhënave:

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Toni pilot përfundon dhe të dhënat fillojnë menjëherë. Pak më vonë, pasi analizuam disa regjistrime të ndryshme audio, arritëm të zbulonim se bajt-i i parë i të dhënave është gjithmonë i njëjtë (10100101b, A5h). Kompjuteri mund të fillojë të lexojë të dhëna pasi t'i marrë ato.

Ju gjithashtu mund t'i kushtoni vëmendje zhvendosjes së pulsit të parë të referencës menjëherë pas 1-së së fundit në bajtin e sinkronizimit. Ai u zbulua shumë më vonë në procesin e zhvillimit të një programi për njohjen e të dhënave, kur të dhënat në fillim të skedarit nuk mund të lexoheshin në mënyrë të qëndrueshme.

Tani le të përpiqemi të përshkruajmë një algoritëm që do të përpunojë një skedar audio dhe do të ngarkojë të dhënat.

Ngarkimi i të dhënave

Së pari, le të shohim disa supozime për ta mbajtur algoritmin të thjeshtë:

  1. Ne do të shqyrtojmë vetëm skedarët në formatin WAV;
  2. Skedari audio duhet të fillojë me një ton pilot dhe nuk duhet të përmbajë heshtje në fillim
  3. Skedari burim duhet të ketë një shpejtësi kampionimi prej 44100 Hz. Në këtë rast, distanca midis pulseve të referencës prej 48 mostrave është përcaktuar tashmë dhe nuk kemi nevojë ta llogarisim atë në mënyrë programore;
  4. Formati i mostrës mund të jetë çdo (8/16 bit/pikë lundruese) - pasi gjatë leximit mund ta konvertojmë në atë të dëshiruar;
  5. Supozojmë se skedari burimor është normalizuar nga amplituda, e cila duhet të stabilizojë rezultatin;

Algoritmi i leximit do të jetë si më poshtë:

  1. Ne lexojmë skedarin në memorie, në të njëjtën kohë konvertojmë formatin e mostrës në 8 bit;
  2. Përcaktoni pozicionin e pulsit të parë në të dhënat audio. Për ta bërë këtë, duhet të llogaritni numrin e mostrës me amplituda maksimale. Për thjeshtësi, do ta llogarisim një herë me dorë. Le ta ruajmë atë në variablin prev_pos;
  3. Shtoni 48 në pozicionin e pulsit të fundit (pos := prev_pos + 48)
  4. Meqenëse rritja e pozicionit me 48 nuk garanton që do të arrijmë në pozicionin e pulsit të referencës tjetër (defekte të shiritit, funksionim i paqëndrueshëm i mekanizmit të drejtimit të shiritit, etj.), Ne duhet të rregullojmë pozicionin e pulsit pos. Për ta bërë këtë, merrni një pjesë të vogël të të dhënave (pos-8;pos+8) dhe gjeni vlerën maksimale të amplitudës mbi të. Pozicioni që korrespondon me maksimumin do të ruhet në po. Këtu 8 = 48/6 është një konstante e përftuar eksperimentalisht, e cila garanton se do të përcaktojmë maksimumin e saktë dhe nuk do të ndikojmë në impulset e tjera që mund të jenë afër. Në raste shumë të këqija, kur distanca midis pulseve është shumë më e vogël ose më e madhe se 48, mund të zbatohet një kërkim i detyruar për një impuls, por brenda fushës së artikullit nuk do ta përshkruaj këtë në algoritëm;
  5. Në hapin e mëparshëm, do të ishte gjithashtu e nevojshme të kontrollohet nëse pulsi i referencës është gjetur fare. Kjo do të thotë, nëse thjesht kërkoni maksimumin, kjo nuk garanton që impulsi është i pranishëm në këtë segment. Në zbatimin tim të fundit të programit të leximit, unë kontrolloj ndryshimin midis vlerave të amplitudës maksimale dhe minimale në një segment dhe nëse tejkalon një kufi të caktuar, llogaris praninë e një impulsi. Pyetja është gjithashtu se çfarë të bëni nëse pulsi i referencës nuk gjendet. Ka 2 opsione: ose të dhënat kanë përfunduar dhe heshtja vijon, ose kjo duhet të konsiderohet si një gabim leximi. Megjithatë, ne do ta heqim këtë për të thjeshtuar algoritmin;
  6. Në hapin tjetër, duhet të përcaktojmë praninë e një impulsi të dhënash (bit 0 ose 1), për këtë marrim mesin e segmentit (prev_pos;pos) middle_pos i barabartë me middle_pos := (prev_pos+pos)/2 dhe në një lagje të mesme_pos në segmentin (middle_pos-8;middle_pos +8) le të llogarisim amplituda maksimale dhe minimale. Nëse diferenca ndërmjet tyre është më shumë se 10, ne shkruajmë bitin 1 në rezultat, përndryshe 0. 10 është një konstante e përftuar eksperimentalisht;
  7. Ruani pozicionin aktual në prev_pos (prev_pos := pos)
  8. Përsëriteni duke filluar nga hapi 3 derisa të lexojmë të gjithë skedarin;
  9. Vargu i biteve që rezulton duhet të ruhet si një grup bajtësh. Meqenëse nuk e kemi marrë parasysh bajtin e sinkronizimit gjatë leximit, numri i biteve mund të mos jetë shumëfish i 8, dhe kompensimi i kërkuar i bitit është gjithashtu i panjohur. Në zbatimin e parë të algoritmit, unë nuk dija për ekzistencën e bajtit të sinkronizimit dhe për këtë arsye thjesht ruajta 8 skedarë me numra të ndryshëm të biteve të kompensimit. Njëri prej tyre përmbante të dhëna të sakta. Në algoritmin përfundimtar, unë thjesht heq të gjitha pjesët deri në A5h, gjë që më lejon të marr menjëherë skedarin e saktë të daljes

Algoritmi në Ruby, për të interesuarit
Zgjodha Ruby si gjuhë për të shkruar programin, sepse... Unë programoj në të shumicën e kohës. Opsioni nuk është me performancë të lartë, por detyra për të bërë shpejtësinë e leximit sa më shpejt të jetë e mundur nuk ia vlen.

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

Result

Pasi provova disa variante të algoritmit dhe konstanteve, pata fatin të marr diçka jashtëzakonisht interesante:

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Pra, duke gjykuar nga vargjet e karaktereve, ne kemi një program për vizatimin e grafikëve. Megjithatë, nuk ka fjalë kyçe në tekstin e programit. Të gjitha fjalët kyçe janë të koduara si bajt (secila vlerë > 80h). Tani duhet të zbulojmë se cili kompjuter nga vitet '80 mund të ruante programe në këtë format.

Në fakt, është shumë i ngjashëm me një program BASIC. Kompjuteri ZX Spectrum ruan programet në përafërsisht të njëjtin format në memorie dhe i ruan programet në kasetë. Vetëm në rast, unë kontrollova fjalët kyçe kundër tabela. Megjithatë, rezultati ishte dukshëm negativ.

Kontrollova gjithashtu fjalët kyçe BASIC të Atari, Commodore 64 dhe disa kompjuterë të tjerë të asaj kohe, për të cilët arrita të gjeja dokumentacion, por pa sukses - njohuritë e mia për llojet e kompjuterëve retro doli të ishin jo aq të gjera.

Pastaj vendosa të shkoj Lista, dhe pastaj vështrimi im ra në emrin e prodhuesit Radio Shack dhe kompjuterit TRS-80. Këta janë emrat që shkruheshin në etiketat e kasetave që ishin shtrirë në tavolinën time! Nuk i njihja më parë këta emra dhe nuk isha i njohur me kompjuterin TRS-80, kështu që më dukej se Radio Shack ishte një prodhues i kasetave audio si BASF, Sony ose TDK, dhe TRS-80 ishte koha e riprodhimit. Pse jo?

Kompjuteri Tandy/Radio Kasolle TRS-80

Ka shumë të ngjarë që regjistrimi audio në fjalë, të cilin e dhashë si shembull në fillim të artikullit, të jetë bërë në një kompjuter si ky:

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Doli që ky kompjuter dhe varietetet e tij (Model I/Model III/Model IV, etj.) ishin shumë të njohura në një kohë (natyrisht, jo në Rusi). Vlen të përmendet se procesori që ata përdorën ishte gjithashtu Z80. Për këtë kompjuter mund të gjeni në internet shumë informacion. Në vitet '80, informacioni kompjuterik u shpërnda në revista. Për momentin ka disa emulatorë kompjuterë për platforma të ndryshme.

Kam shkarkuar emulatorin trs80gp dhe për herë të parë munda të shikoja se si funksiononte ky kompjuter. Sigurisht, kompjuteri nuk mbështeti daljen e ngjyrave; rezolucioni i ekranit ishte vetëm 128x48 piksele, por kishte shumë shtesa dhe modifikime që mund të rrisnin rezolucionin e ekranit. Kishte gjithashtu shumë opsione për sistemet operative për këtë kompjuter dhe opsione për zbatimin e gjuhës BASIC (e cila, ndryshe nga ZX Spectrum, në disa modele as nuk ishte "flash" në ROM dhe çdo opsion mund të ngarkohej nga një floppy disk, ashtu si vetë OS)

gjeta gjithashtu dobishmërisë për të kthyer regjistrimet audio në formatin CAS, i cili mbështetet nga emulatorët, por për disa arsye nuk ishte e mundur të lexoheshin regjistrimet nga kasetat e mia duke i përdorur ato.

Pasi kuptova formatin e skedarit CAS (i ​​cili doli të ishte vetëm një kopje pak nga pak e të dhënave nga kaseta që kisha tashmë në dorë, përveç kokës me praninë e një bajt sinkronizimi), bëra një disa ndryshime në programin tim dhe isha në gjendje të nxirrja një skedar CAS që funksiononte në emulator (TRS-80 Model III):

Si i rikuperova të dhënat në një format të panjohur nga shiriti magnetik

Kam projektuar versionin më të fundit të mjetit të konvertimit me përcaktimin automatik të pulsit të parë dhe distancën midis pulseve të referencës si një paketë GEM, kodi burim është i disponueshëm në Github.

Përfundim

Rruga që kemi bërë doli të jetë një udhëtim magjepsës në të kaluarën dhe më vjen mirë që në fund gjeta përgjigjen. Ndër të tjera unë:

  • Kuptova formatin për ruajtjen e të dhënave në spektrin ZX dhe studiova rutinat e integruara të ROM-it për ruajtjen/leximin e të dhënave nga kasetat audio
  • U njoha me kompjuterin TRS-80 dhe varietetet e tij, studiova sistemin operativ, shikova programet e mostrës dhe madje pata mundësinë të bëj korrigjimin e kodeve të makinerisë (në fund të fundit, të gjitha mnemonikët Z80 janë të njohur për mua)
  • Shkroi një mjet të plotë për konvertimin e regjistrimeve audio në formatin CAS, i cili mund të lexojë të dhëna që nuk njihen nga programi "zyrtar"

Burimi: www.habr.com

Shto një koment