Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Aizvēsture

Būdams retro aparatūras cienītājs, es reiz iegādājos ZX Spectrum+ no pārdevēja Apvienotajā Karalistē. Komplektā ar pašu datoru saņēmu vairākas audio kasetes ar spēlēm (oriģinālajā iepakojumā ar instrukciju), kā arī kasetēs ierakstītas programmas bez īpašiem marķējumiem. Pārsteidzošā kārtā dati no 40 gadus vecām kasetēm bija labi nolasāmi un no tām varēju lejupielādēt gandrīz visas spēles un programmas.

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Tomēr uz dažām kasetēm atradu ierakstus, kas acīmredzami nav veikti ar ZX Spectrum datoru. Tie skanēja pavisam savādāk un atšķirībā no ierakstiem no minētā datora nesākās ar īsu BASIC bootloader, kāds parasti ir visu programmu un spēļu ierakstos.

Kādu laiku tas mani vajāja – ļoti gribēju noskaidrot, kas viņos slēpjas. Ja jūs varētu nolasīt audio signālu kā baitu secību, jūs varētu meklēt rakstzīmes vai jebko, kas norāda signāla izcelsmi. Sava veida retro-arheoloģija.

Tagad, kad esmu nogājusi visu ceļu un paskatos uz pašu kasešu etiķetēm, es smaidu, jo

atbilde visu laiku bija manā acu priekšā
Uz kreisās kasetes etiķetes ir TRS-80 datora nosaukums un tieši zem ražotāja nosaukuma: “Ražots Radio Shack in USA”

(Ja gribi saglabāt intrigu līdz galam, neliecies zem spoilera)

Audio signālu salīdzinājums

Vispirms digitalizēsim audioierakstus. Varat klausīties, kā tas izklausās:


Un kā parasti skan ieraksts no ZX Spectrum datora:


Abos gadījumos ieraksta sākumā ir t.s pilota tonis - tādas pašas frekvences skaņa (pirmajā ierakstā tā ir ļoti īsa <1 sekunde, bet ir atšķirama). Pilota signāls dod signālu datoram sagatavoties datu saņemšanai. Parasti katrs dators atpazīst tikai savu "savu" pilota signālu pēc signāla formas un frekvences.

Jāsaka kaut kas par pašu signāla formu. Piemēram, ZX Spectrum tā forma ir taisnstūrveida:

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Kad tiek noteikts pilota signāls, ZX Spectrum uz ekrāna malas parāda mainīgas sarkanas un zilas joslas, kas norāda, ka signāls ir atpazīts. Pilota signāls beidzas sinhronais impulss, kas dod signālu datoram sākt datu saņemšanu. To raksturo īsāks ilgums (salīdzinājumā ar pilota signālu un turpmākajiem datiem) (sk. attēlu)

Pēc sinhronizācijas impulsa saņemšanas dators reģistrē katru signāla pieaugumu/kritumu, mērot tā ilgumu. Ja ilgums ir mazāks par noteiktu robežu, atmiņā tiek ierakstīts bits 1, pretējā gadījumā 0. Biti tiek savākti baitos un process tiek atkārtots, līdz tiek saņemti N baiti. Skaitlis N parasti tiek ņemts no lejupielādētā faila galvenes. Iekraušanas secība ir šāda:

  1. pilota tonis
  2. galvene (fiksēts garums), satur lejupielādēto datu lielumu (N), faila nosaukumu un veidu
  3. pilota tonis
  4. paši dati

Lai pārliecinātos par datu pareizu ielādi, ZX Spectrum nolasa t.s paritātes baits (paritātes baits), kas tiek aprēķināts, saglabājot failu, XORingojot visus rakstīto datu baitus. Nolasot failu, dators no saņemtajiem datiem aprēķina paritātes baitu un, ja rezultāts atšķiras no saglabātā, parāda kļūdas ziņojumu “R Tape loading error”. Stingri sakot, dators var izdot šo ziņojumu agrāk, ja lasīšanas laikā tas nevar atpazīt impulsu (nokavēts vai tā ilgums neatbilst noteiktiem ierobežojumiem)

Tātad, tagad redzēsim, kā izskatās nezināms signāls:

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Šis ir pilota signāls. Signāla forma ievērojami atšķiras, taču ir skaidrs, ka signāls sastāv no noteiktas frekvences īsu impulsu atkārtošanās. Pie iztveršanas frekvences 44100 Hz attālums starp “pīķiem” ir aptuveni 48 paraugi (kas atbilst ~918 Hz frekvencei). Atcerēsimies šo skaitli.

Tagad apskatīsim datu fragmentu:

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Ja izmērām attālumu starp atsevišķiem impulsiem, izrādās, ka attālums starp “garajiem” impulsiem joprojām ir ~48 paraugi, bet starp īsajiem – ~24. Nedaudz skatoties uz priekšu, teikšu, ka beigās izrādījās, ka “atsauces” impulsi ar frekvenci 918 Hz seko nepārtraukti, no faila sākuma līdz beigām. Var pieņemt, ka, pārsūtot datus, ja starp atsauces impulsiem rodas papildu impulss, mēs to uzskatām par bitu 1, pretējā gadījumā par 0.

Kā ar sinhronizācijas impulsu? Apskatīsim datu sākumu:

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Pilotnes signāls beidzas, un dati sākas nekavējoties. Nedaudz vēlāk, analizējot vairākus dažādus audio ierakstus, mēs varējām atklāt, ka pirmais datu baits vienmēr ir vienāds (10100101b, A5h). Dators var sākt lasīt datus pēc to saņemšanas.

Varat arī pievērst uzmanību pirmā atsauces impulsa nobīdei tūlīt pēc pēdējā 1. sinhronizācijas baitā. Tas tika atklāts daudz vēlāk datu atpazīšanas programmas izstrādes procesā, kad faila sākumā esošos datus nevarēja stabili nolasīt.

Tagad mēģināsim aprakstīt algoritmu, kas apstrādās audio failu un ielādēs datus.

Notiek datu ielāde

Vispirms apskatīsim dažus pieņēmumus, lai algoritms būtu vienkāršs:

  1. Mēs izskatīsim tikai failus WAV formātā;
  2. Audio failam jāsākas ar pilotsignālu, un tā sākumā nedrīkst būt klusums
  3. Avota faila iztveršanas frekvencei ir jābūt 44100 Hz. Šajā gadījumā attālums starp 48 paraugu atsauces impulsiem jau ir noteikts, un mums tas nav jāaprēķina programmatiski;
  4. Parauga formāts var būt jebkurš (8/16 biti/peldošais komats) – tā kā lasot varam konvertēt uz vēlamo;
  5. Mēs pieņemam, ka avota fails ir normalizēts pēc amplitūdas, kam vajadzētu stabilizēt rezultātu;

Lasīšanas algoritms būs šāds:

  1. Mēs nolasām failu atmiņā, tajā pašā laikā pārveidojot parauga formātu uz 8 bitiem;
  2. Nosakiet pirmā impulsa pozīciju audio datos. Lai to izdarītu, jums jāaprēķina parauga skaits ar maksimālo amplitūdu. Vienkāršības labad mēs to vienreiz aprēķināsim manuāli. Saglabāsim to mainīgajā prev_pos;
  3. Pievienojiet 48 pēdējā impulsa pozīcijai (poz := prev_pos + 48)
  4. Tā kā pozīcijas palielināšana par 48 negarantē, ka nokļūsim līdz nākamā atskaites impulsa pozīcijai (lentes defekti, nestabila lentes piedziņas mehānisma darbība u.c.), tad mums ir jāpielāgo impulsa pozīcija poz. Lai to izdarītu, paņemiet nelielu datu daļu (pos-8;pos+8) un atrodiet tajā maksimālo amplitūdas vērtību. Pozīcija, kas atbilst maksimumam, tiks saglabāta pozīcijā. Šeit 8 = 48/6 ir eksperimentāli iegūta konstante, kas garantē, ka noteiksim pareizo maksimumu un neietekmēs citus impulsus, kas var būt tuvumā. Ļoti sliktos gadījumos, kad attālums starp impulsiem ir daudz mazāks vai lielāks par 48, jūs varat ieviest impulsa piespiedu meklēšanu, taču raksta ietvaros es to neaprakstīšu algoritmā;
  5. Iepriekšējā darbībā būtu arī jāpārbauda, ​​vai atskaites impulss vispār tika atrasts. Tas ir, ja jūs vienkārši meklējat maksimumu, tas negarantē, ka impulss ir šajā segmentā. Savā jaunākajā lasīšanas programmas realizācijā es pārbaudu atšķirību starp segmenta maksimālo un minimālo amplitūdas vērtībām, un, ja tā pārsniedz noteiktu robežu, es uzskaitu impulsa klātbūtni. Jautājums ir arī par to, ko darīt, ja atsauces impulss nav atrasts. Ir 2 iespējas: vai nu dati ir beigušies un seko klusums, vai arī tas jāuzskata par lasīšanas kļūdu. Tomēr mēs to izlaidīsim, lai vienkāršotu algoritmu;
  6. Nākamajā solī mums ir jānosaka datu impulsa klātbūtne (bits 0 vai 1), šim nolūkam mēs ņemam segmenta vidusdaļu (prev_pos;pos) middle_pos, kas vienāds ar middle_pos := (prev_pos+pos)/2 un kādā apkaimē segmenta vidus_pozīcija (middle_pos-8;middle_pos +8) aprēķināsim maksimālo un minimālo amplitūdu. Ja starpība starp tām ir lielāka par 10, rezultātam ierakstām bitu 1, pretējā gadījumā 0. 10 ir eksperimentāli iegūta konstante;
  7. Saglabāt pašreizējo pozīciju prev_pos (prev_pos := poz)
  8. Atkārtojiet, sākot no 3. darbības, līdz tiek izlasīts viss fails;
  9. Iegūtais bitu masīvs ir jāsaglabā kā baitu kopa. Tā kā lasīšanas laikā mēs neņēmām vērā sinhronizācijas baitu, bitu skaits var nebūt reizināts ar 8, un arī nepieciešamā bitu nobīde nav zināma. Pirmajā algoritma realizācijā es nezināju par sinhronizācijas baita esamību un tāpēc vienkārši saglabāju 8 failus ar dažādu nobīdes bitu skaitu. Vienā no tiem bija pareizi dati. Pēdējā algoritmā es vienkārši noņemu visus bitus līdz A5h, kas ļauj man nekavējoties iegūt pareizo izvades failu

Algoritms rubīnā, interesentiem
Par programmas rakstīšanas valodu izvēlējos Rubīnu, jo... Es uz to programmēju lielāko daļu laika. Opcija nav augstas veiktspējas, taču uzdevums padarīt lasīšanas ātrumu pēc iespējas ātrāku nav tā vērts.

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

Piedzīvojiet efektīvu rezultātu spēku

Izmēģinājusi vairākus algoritma un konstantu variantus, man paveicās iegūt kaut ko ārkārtīgi interesantu:

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Tātad, spriežot pēc rakstzīmju virknēm, mums ir programma grafiku zīmēšanai. Tomēr programmas tekstā nav atslēgvārdu. Visi atslēgvārdi tiek kodēti kā baiti (katra vērtība > 80 h). Tagad jānoskaidro, kurš dators no 80. gadiem varētu saglabāt programmas šajā formātā.

Patiesībā tā ir ļoti līdzīga BASIC programmai. Dators ZX Spectrum saglabā programmas aptuveni tādā pašā formātā atmiņā un saglabā programmas lentē. Katram gadījumam es pārbaudīju atslēgvārdus tabula. Tomēr rezultāts bija acīmredzami negatīvs.

Pārbaudīju arī tā laika populāro Atari, Commodore 64 un vairāku citu datoru BASIC atslēgas vārdus, kuriem izdevās atrast dokumentāciju, taču nesekmīgi - manas zināšanas par retro datoru veidiem izrādījās ne tik plašas.

Tad es nolēmu iet saraksts, un tad mans skatiens nokrita uz ražotāja Radio Shack nosaukumu un datoru TRS-80. Tie ir vārdi, kas bija rakstīti uz kasešu etiķetēm, kas gulēja uz mana galda! Es iepriekš nezināju šos nosaukumus un nebiju pazīstams ar datoru TRS-80, tāpēc man šķita, ka Radio Shack ir audiokasešu ražotājs, piemēram, BASF, Sony vai TDK, un TRS-80 bija atskaņošanas laiks. Kāpēc ne?

Dators Tandy/Radio Shack TRS-80

Ļoti iespējams, ka attiecīgais audio ieraksts, kuru raksta sākumā minēju kā piemēru, ir veikts ar šādu datoru:

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Izrādījās, ka šis dators un tā šķirnes (Model I/Model III/Model IV u.c.) savulaik bija ļoti populāri (protams, ne Krievijā). Jāatzīmē, ka procesors, ko viņi izmantoja, bija arī Z80. Šim datoram jūs varat atrast internetā daudz informācijas. 80. gados datorinformācija tika izplatīta žurnāli. Šobrīd tādas ir vairākas emulatori datori dažādām platformām.

Es lejupielādēju emulatoru trs80gp un pirmo reizi man bija iespēja redzēt, kā šis dators darbojas. Protams, dators neatbalstīja krāsu izvadi, ekrāna izšķirtspēja bija tikai 128x48 pikseļi, taču bija daudz paplašinājumu un modifikāciju, kas varēja palielināt ekrāna izšķirtspēju. Bija arī daudz opciju šī datora operētājsistēmām un BASIC valodas ieviešanas iespējas (kas atšķirībā no ZX Spectrum dažos modeļos pat netika “uzplaiksnīta” ROM un jebkuru opciju varēja ielādēt no disketes, tāpat kā pati OS)

Es arī atradu lietderība konvertēt audio ierakstus CAS formātā, ko atbalsta emulatori, bet nez kāpēc nebija iespējams nolasīt ierakstus no manām kasetēm, izmantojot tos.

Noskaidrojis CAS faila formātu (kas izrādījās tikai pa bitiem datu kopija no kasetes, kas man jau bija pa rokai, izņemot galveni ar sinhronizācijas baita klātbūtni), es izveidoju dažas izmaiņas manā programmā un varēju izvadīt strādājošu CAS failu, kas darbojās emulatorā (TRS-80 Model III):

Kā es atguvu datus nezināmā formātā no magnētiskās lentes

Es izstrādāju jaunāko konvertēšanas utilīta versiju ar automātisku pirmā impulsa un attāluma starp atsauces impulsiem noteikšanu kā GEM pakotni, avota kods ir pieejams vietnē GitHub.

Secinājums

Ceļš, ko esam nogājuši, izvērtās par aizraujošu ceļojumu pagātnē, un es priecājos, ka galu galā atradu atbildi. Cita starpā es:

  • Es izdomāju datu saglabāšanas formātu ZX Spectrum un izpētīju iebūvētās ROM rutīnas datu saglabāšanai/nolasīšanai no audio kasetēm
  • Es iepazinos ar datoru TRS-80 un tā veidiem, pētīju operētājsistēmu, apskatīju programmu paraugus un pat man bija iespēja veikt atkļūdošanu mašīnu kodos (galu galā visas Z80 mnemonikas man ir pazīstamas)
  • Uzrakstīja pilnvērtīgu utilītu audio ierakstu konvertēšanai CAS formātā, kas var nolasīt datus, kurus “oficiālā” utilīta neatpazīst.

Avots: www.habr.com

Pievieno komentāru