Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Sana oldin

Retro-uskunalar ishqibozi sifatida men bir marta Buyuk Britaniyadagi sotuvchidan ZX Spectrum+ sotib oldim. Kompyuterning o'zi bilan birga men o'yinlar bilan bir nechta audio kassetalarni oldim (ko'rsatmalar bilan original qadoqda), shuningdek, maxsus belgilarsiz kasetlarda yozilgan dasturlar. Ajablanarlisi shundaki, 40 yoshli kassetalardagi ma'lumotlar yaxshi o'qilishi mumkin edi va men ulardan deyarli barcha o'yinlar va dasturlarni yuklab olishga muvaffaq bo'ldim.

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Biroq, ba'zi kasetlarda men ZX Spectrum kompyuteri tomonidan aniqlanmagan yozuvlarni topdim. Ular butunlay boshqacha yangradi va yuqorida aytib o'tilgan kompyuterdagi yozuvlardan farqli o'laroq, ular odatda barcha dasturlar va o'yinlarning yozuvlarida mavjud bo'lgan qisqa BASIC yuklovchi bilan boshlanmadi.

Bir muncha vaqt bu meni hayratda qoldirdi - men ularda nima yashiringanini bilishni juda xohlardim. Agar siz audio signalni baytlar ketma-ketligi sifatida o'qiy olsangiz, signalning kelib chiqishini ko'rsatadigan belgilar yoki har qanday narsani qidirib topishingiz mumkin. Retro-arxeologiyaning bir turi.

Endi men hamma yo'lni bosib o'tib, kassetalarning yorliqlarini ko'rib chiqdim, chunki men tabassum qilaman

javob hamma vaqt ko'zim oldida edi
Chap kassetaning yorlig'ida TRS-80 kompyuterining nomi va ishlab chiqaruvchi nomi ostida: "AQShda Radio Shack tomonidan ishlab chiqarilgan"

(Agar siz intrigani oxirigacha saqlamoqchi bo'lsangiz, spoylerga tushmang)

Ovozli signallarni taqqoslash

Avvalo, audioyozuvlarni raqamlashtiramiz. Bu qanday eshitilishini tinglashingiz mumkin:


Odatdagidek ZX Spectrum kompyuteridan yozuv eshitiladi:


Ikkala holatda ham, yozuvning boshida, deb ataladigan narsa bor uchuvchi ohang - bir xil chastotali tovush (birinchi yozuvda u juda qisqa <1 soniya, lekin ajralib turadi). Uchuvchi ohang kompyuterga ma'lumotlarni qabul qilishga tayyorlanish uchun signal beradi. Qoida tariqasida, har bir kompyuter signalning shakli va chastotasi bo'yicha faqat o'zining "o'z" uchuvchi ohangini taniydi.

Signal shaklining o'zi haqida biror narsa aytish kerak. Masalan, ZX Spectrumda uning shakli to'rtburchaklar shaklida bo'ladi:

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Uchuvchi ohang aniqlanganda, ZX Spectrum signal tan olinganligini ko'rsatish uchun ekran chegarasida o'zgaruvchan qizil va ko'k chiziqlarni ko'rsatadi. Uchuvchi ohang tugaydi sinxron puls, bu kompyuterga ma'lumotlarni qabul qilishni boshlash uchun signal beradi. U qisqaroq muddat bilan tavsiflanadi (uchuvchi ohang va keyingi ma'lumotlarga nisbatan) (rasmga qarang)

Sinxronlash pulsi qabul qilingandan so'ng, kompyuter signalning har bir ko'tarilishi / tushishini qayd etadi, uning davomiyligini o'lchaydi. Agar davomiylik ma'lum chegaradan kam bo'lsa, 1-bit xotiraga yoziladi, aks holda 0. Bitlar baytlarga yig'iladi va jarayon N bayt olinmaguncha takrorlanadi. N raqami odatda yuklab olingan faylning sarlavhasidan olinadi. Yuklash ketma-ketligi quyidagicha:

  1. uchuvchi ohang
  2. sarlavha (belgilangan uzunlik), yuklab olingan ma'lumotlarning hajmini (N), fayl nomini va turini o'z ichiga oladi
  3. uchuvchi ohang
  4. ma'lumotlarning o'zi

Ma'lumotlar to'g'ri yuklanganligiga ishonch hosil qilish uchun ZX Spectrum deb ataladigan narsani o'qiydi paritet bayt (parite bayti), bu yozma ma'lumotlarning barcha baytlarini XORlash orqali faylni saqlashda hisoblanadi. Faylni o'qiyotganda, kompyuter olingan ma'lumotlardan paritet baytni hisoblab chiqadi va agar natija saqlanganidan farq qilsa, "R Tape loading error" xato xabarini ko'rsatadi. To'g'ridan-to'g'ri aytganda, agar kompyuter o'qish paytida pulsni taniy olmasa (o'tkazib yuborilgan yoki uning davomiyligi ma'lum chegaralarga to'g'ri kelmasa) ushbu xabarni oldinroq berishi mumkin.

Keling, noma'lum signal qanday ko'rinishini ko'rib chiqaylik:

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Bu uchuvchi ohang. Signalning shakli sezilarli darajada farq qiladi, ammo signal ma'lum bir chastotaning qisqa impulslarini takrorlashdan iboratligi aniq. Namuna olish chastotasi 44100 Gts bo'lganida, "cho'qqilar" orasidagi masofa taxminan 48 ta namunani tashkil qiladi (bu ~ 918 Gts chastotaga to'g'ri keladi) Keling, ushbu raqamni eslaylik.

Endi ma'lumotlar fragmentini ko'rib chiqamiz:

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Agar individual impulslar orasidagi masofani o'lchaydigan bo'lsak, "uzoq" impulslar orasidagi masofa hali ham ~ 48 namuna, qisqa bo'lganlar orasida - ~ 24 ekanligi ma'lum bo'ladi. Bir oz oldinga qarab, shuni aytamanki, oxir-oqibat 918 Gts chastotali "mos yozuvlar" impulslari faylning boshidan oxirigacha doimiy ravishda kuzatib borishi ma'lum bo'ldi. Taxmin qilish mumkinki, ma'lumotlarni uzatishda, agar mos yozuvlar impulslari orasida qo'shimcha impuls uchrasa, biz uni bit 1, aks holda 0 deb hisoblaymiz.

Sinxronlash pulsi haqida nima deyish mumkin? Keling, ma'lumotlarning boshiga qaraylik:

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Uchuvchi ohang tugaydi va ma'lumotlar darhol boshlanadi. Biroz vaqt o'tgach, bir nechta turli xil audio yozuvlarni tahlil qilgandan so'ng, biz ma'lumotlarning birinchi bayti har doim bir xil ekanligini aniqladik (10100101b, A5h). Kompyuter ma'lumotlarni qabul qilgandan keyin o'qishni boshlashi mumkin.

Sinxronlash baytidagi oxirgi 1-dan so'ng darhol birinchi mos yozuvlar pulsining siljishiga ham e'tibor berishingiz mumkin. U ancha keyinroq ma'lumotlarni aniqlash dasturini ishlab chiqish jarayonida, faylning boshidagi ma'lumotlarni barqaror o'qish mumkin bo'lmaganda aniqlangan.

Endi audio faylga ishlov beradigan va ma'lumotlarni yuklaydigan algoritmni tasvirlashga harakat qilaylik.

Ma'lumotlar yuklanmoqda

Birinchidan, algoritmni sodda saqlash uchun bir nechta taxminlarni ko'rib chiqaylik:

  1. Biz faqat WAV formatidagi fayllarni ko'rib chiqamiz;
  2. Audio fayl uchuvchi ohang bilan boshlanishi kerak va boshida sukunat bo'lmasligi kerak
  3. Manba fayli 44100 Gts namuna olish tezligiga ega bo'lishi kerak. Bunday holda, 48 ta namunaning mos yozuvlar pulslari orasidagi masofa allaqachon aniqlangan va biz uni dasturiy tarzda hisoblashimiz shart emas;
  4. Namuna formati har qanday bo'lishi mumkin (8/16 bit / suzuvchi nuqta) - chunki o'qish paytida biz uni kerakli formatga o'zgartirishimiz mumkin;
  5. Biz manba fayli amplituda bilan normallashtirilgan deb hisoblaymiz, bu esa natijani barqarorlashtirishi kerak;

O'qish algoritmi quyidagicha bo'ladi:

  1. Biz faylni xotiraga o'qiymiz, shu bilan birga namuna formatini 8 bitga aylantiramiz;
  2. Ovoz ma'lumotlaridagi birinchi impulsning o'rnini aniqlang. Buning uchun siz maksimal amplitudali namunaning sonini hisoblashingiz kerak. Oddiylik uchun biz uni bir marta qo'lda hisoblaymiz. Keling, uni prev_pos o'zgaruvchisiga saqlaymiz;
  3. Oxirgi pulsning holatiga 48 qo'shing (pos := prev_pos + 48)
  4. Pozitsiyani 48 ga oshirish biz keyingi mos yozuvlar impulsining holatiga (lenta nuqsonlari, lenta qo'zg'alish mexanizmining beqaror ishlashi va boshqalar) etib borishimizga kafolat bermasligi sababli, biz pos impulsining holatini sozlashimiz kerak. Buning uchun kichik ma'lumot qismini (pos-8;pos+8) oling va undagi maksimal amplituda qiymatini toping. Maksimalga mos keladigan pozitsiya posda saqlanadi. Bu erda 8 = 48/6 eksperimental ravishda olingan konstanta bo'lib, biz to'g'ri maksimalni aniqlashimizni va yaqin atrofdagi boshqa impulslarga ta'sir qilmasligimizni kafolatlaydi. Juda yomon holatlarda, impulslar orasidagi masofa 48 dan ancha kam yoki undan katta bo'lsa, siz impulsni majburiy qidirishni amalga oshirishingiz mumkin, ammo maqola doirasida men buni algoritmda tasvirlamayman;
  5. Oldingi bosqichda, shuningdek, mos yozuvlar pulsning umuman topilganligini tekshirish kerak bo'ladi. Ya'ni, agar siz shunchaki maksimalni qidirsangiz, bu impulsning ushbu segmentda mavjudligini kafolatlamaydi. O'qish dasturini so'nggi amalga oshirishda men segmentdagi maksimal va minimal amplituda qiymatlari o'rtasidagi farqni tekshiraman va agar u ma'lum chegaradan oshsa, impuls mavjudligini hisoblayman. Savol, shuningdek, mos yozuvlar pulsi topilmasa, nima qilish kerakligi. Ikkita variant mavjud: yoki ma'lumotlar tugadi va sukunat davom etadi yoki bu o'qish xatosi deb hisoblanishi kerak. Biroq, algoritmni soddalashtirish uchun biz buni o'tkazib yuboramiz;
  6. Keyingi bosqichda biz ma'lumotlar impulsi mavjudligini aniqlashimiz kerak (bit 0 yoki 1), buning uchun segmentning o'rtasini (prev_pos;pos) middle_pos ga teng bo'lgan middle_pos := (prev_pos+pos)/2 va segmentdagi Middle_pos ning ba'zi bir mahallasida (middle_pos-8;middle_pos +8) maksimal va minimal amplitudani hisoblaymiz. Agar ular orasidagi farq 10 dan ortiq bo'lsa, natijaga 1 bitni yozamiz, aks holda 0. 10 - tajriba yo'li bilan olingan doimiy;
  7. Joriy pozitsiyani oldingi_postda saqlang (oldingi_post := pos)
  8. 3-bosqichdan boshlab butun faylni o'qiguncha takrorlang;
  9. Olingan bit massivi baytlar to'plami sifatida saqlanishi kerak. Biz o'qishda sinxronlash baytini hisobga olmaganimiz sababli, bitlar soni 8 ga ko'paytirilmasligi mumkin va kerakli bit ofset ham noma'lum. Algoritmni birinchi amalga oshirishda men sinxronlash bayti mavjudligi haqida bilmasdim va shuning uchun turli xil ofset bitlari bilan 8 ta faylni saqlab qoldim. Ulardan biri to'g'ri ma'lumotlarni o'z ichiga olgan. Yakuniy algoritmda men A5h gacha bo'lgan barcha bitlarni olib tashlayman, bu menga to'g'ri chiqish faylini darhol olish imkonini beradi.

Qiziqqanlar uchun Ruby-dagi algoritm
Men dasturni yozish uchun til sifatida Ruby ni tanladim, chunki... Men ko'pincha uni dasturlashtiraman. Variant yuqori unumdorlikka ega emas, lekin o'qish tezligini imkon qadar tezroq qilish vazifasi bunga loyiq emas.

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

natija

Algoritm va konstantalarning bir nechta variantini sinab ko'rganimdan so'ng, men juda qiziqarli narsani olish baxtiga muyassar bo'ldim:

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Shunday qilib, belgilar qatoriga qarab, bizda grafiklarni chizish uchun dastur mavjud. Biroq, dastur matnida kalit so'zlar mavjud emas. Barcha kalit so'zlar bayt sifatida kodlangan (har bir qiymat > 80h). Endi biz 80-yillardagi qaysi kompyuter dasturlarni ushbu formatda saqlashi mumkinligini aniqlashimiz kerak.

Aslida, u BASIC dasturiga juda o'xshaydi. ZX Spectrum kompyuteri dasturlarni taxminan bir xil formatda xotirada saqlaydi va dasturlarni lentaga saqlaydi. Har holda, men kalit so'zlarni qarshi tekshirdim stol. Biroq, natija aniq salbiy edi.

Men shuningdek, o'sha davrdagi mashhur Atari, Commodore 64 va boshqa bir nechta kompyuterlarning BASIC kalit so'zlarini tekshirdim, ular uchun hujjatlarni topa oldim, ammo muvaffaqiyatga erishmadi - retro kompyuterlar turlari haqidagi bilimim unchalik keng emas edi.

Keyin men borishga qaror qildim ro'yxat, va keyin mening nigohim ishlab chiqaruvchi Radio Shack va TRS-80 kompyuterining nomiga tushdi. Mening stolim ustida yotgan kassetalarning yorliqlarida shunday ismlar yozilgan edi! Men bu nomlarni avval bilmasdim va TRS-80 kompyuteri bilan tanish emas edim, shuning uchun menga Radio Shack BASF, Sony yoki TDK kabi audio kassetalar ishlab chiqaruvchisi, TRS-80 esa ijro vaqti edi. Nimaga yo'q?

Kompyuter Tandy/Radio Shack TRS-80

Maqolaning boshida misol tariqasida keltirgan ushbu audioyozuv kompyuterda shunday qilingan bo'lishi mumkin:

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Ma'lum bo'lishicha, ushbu kompyuter va uning navlari (Model I/Model III/Model IV va boshqalar) bir vaqtlar juda mashhur bo'lgan (albatta, Rossiyada emas). E'tiborlisi, ular ishlatgan protsessor ham Z80 edi. Ushbu kompyuter uchun siz Internetda topishingiz mumkin juda ko'p ma'lumotlar. 80-yillarda kompyuter ma'lumotlari tarqatildi jurnallar. Ayni paytda bir nechtasi bor emulyatorlar turli platformalar uchun kompyuterlar.

Men emulyatorni yuklab oldim trs80gp va birinchi marta bu kompyuter qanday ishlashini ko'rishga muvaffaq bo'ldim. Albatta, kompyuter rangli chiqishni qo'llab-quvvatlamadi, ekran o'lchamlari atigi 128x48 piksel edi, lekin ekran o'lchamlarini oshirishi mumkin bo'lgan ko'plab kengaytmalar va modifikatsiyalar mavjud edi. Shuningdek, ushbu kompyuter uchun operatsion tizimlar va BASIC tilini amalga oshirish uchun ko'plab variantlar mavjud edi (bu ZX Spectrum-dan farqli o'laroq, ba'zi modellarda hatto ROMga "yonib-o'chirilmagan" va har qanday variantni floppi diskdan yuklash mumkin edi, xuddi shu kabi. OTning o'zi)

Men ham topdim qulaylik audio yozuvlarni emulyatorlar tomonidan qo'llab-quvvatlanadigan CAS formatiga aylantirish uchun, lekin negadir ular yordamida mening kasetlarimdagi yozuvlarni o'qish mumkin bo'lmadi.

CAS fayl formatini aniqlab, (bu menda allaqachon mavjud bo'lgan lentadagi ma'lumotlarning bir oz nusxasi bo'lib chiqdi, sinxronlash bayti mavjud bo'lgan sarlavhadan tashqari) Mening dasturimga bir nechta o'zgarishlar kiritildi va emulyatorda ishlaydigan ishlaydigan CAS faylini chiqara oldim (TRS-80 Model III):

Qanday qilib magnit lentadan noma'lum formatdagi ma'lumotlarni qayta tikladim

Men birinchi pulsni va mos yozuvlar pulslari orasidagi masofani GEM to'plami sifatida avtomatik aniqlash bilan konversiya yordam dasturining so'nggi versiyasini ishlab chiqdim, manba kodi quyidagi manzilda mavjud. Github.

xulosa

Biz bosib o'tgan yo'l o'tmishga bo'lgan maroqli sayohat bo'lib chiqdi va yakunda javob topganimdan xursandman. Boshqa narsalar qatorida men:

  • Men ZX Spectrum-da ma'lumotlarni saqlash formatini aniqladim va audio kassetalardan ma'lumotlarni saqlash/o'qish uchun o'rnatilgan ROM tartiblarini o'rgandim.
  • Men TRS-80 kompyuteri va uning turlari bilan tanishdim, operatsion tizimni o'rgandim, namunaviy dasturlarni ko'rib chiqdim va hatto mashina kodlarida disk raskadrovka qilish imkoniyatiga ega bo'ldim (axir, barcha Z80 mnemonikalari menga tanish)
  • "Rasmiy" yordam dasturi tomonidan tan olinmagan ma'lumotlarni o'qiy oladigan audio yozuvlarni CAS formatiga o'tkazish uchun to'liq yordamchi dastur yozildi.

Manba: www.habr.com

a Izoh qo'shish