Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Prehistorya

Retro avadanlığın həvəskarı olduğum üçün bir dəfə Böyük Britaniyadakı bir satıcıdan ZX Spectrum+ aldım. Kompüterin özü ilə birlikdə mən oyunları olan bir neçə audio kaset aldım (təlimatlar ilə orijinal qablaşdırmada), həmçinin xüsusi işarələri olmayan kasetlərdə yazılmış proqramlar. Təəccüblüdür ki, 40 illik kasetlərdən olan məlumatlar yaxşı oxunurdu və mən onlardan demək olar ki, bütün oyunları və proqramları yükləyə bildim.

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Bununla belə, bəzi kasetlərdə ZX Spectrum kompüteri tərəfindən açıq-aydın edilməmiş yazılar tapdım. Onlar tamamilə fərqli səslənirdilər və qeyd olunan kompüterdəki yazılardan fərqli olaraq, ümumiyyətlə bütün proqramların və oyunların qeydlərində olan qısa BASIC yükləyicisi ilə başlamadılar.

Bir müddət bu məni təqib etdi - mən həqiqətən onlarda nəyin gizləndiyini öyrənmək istədim. Əgər siz audio siqnalı bayt ardıcıllığı kimi oxuya bilsəniz, simvolları və ya siqnalın mənşəyini göstərən hər hansı bir şeyi axtara bilərsiniz. Bir növ retro-arxeologiya.

İndi mən bütün yolu getdim və kasetlərin etiketlərinə baxdım, gülümsəyirəm, çünki

cavab gözümün qabağında idi
Sol kasetin etiketində TRS-80 kompüterinin adı və istehsalçının adının bir az altında: “ABŞ-da Radio Shack tərəfindən istehsal edilmişdir”

(Əgər intriqanı sona qədər saxlamaq istəyirsinizsə, spoylerin altına düşməyin)

Səs siqnallarının müqayisəsi

Əvvəlcə səs yazılarını rəqəmsallaşdıraq. Bunun nə kimi səsləndiyini dinləyə bilərsiniz:


Həmişə olduğu kimi ZX Spectrum kompüterindən səs yazısı səslənir:


Hər iki halda, qeydin əvvəlində sözdə bir şey var pilot tonu - eyni tezlikli səs (ilk qeyddə çox qısa <1 saniyə, lakin fərqləndirilir). Pilot ton kompüterə məlumatı qəbul etməyə hazırlaşmaq üçün siqnal verir. Bir qayda olaraq, hər bir kompüter siqnalın forması və tezliyi ilə yalnız "öz" pilot tonunu tanıyır.

Siqnal formasının özü haqqında bir şey söyləmək lazımdır. Məsələn, ZX Spectrum-da onun forması düzbucaqlıdır:

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Pilot ton aşkar edildikdə, ZX Spectrum siqnalın tanındığını göstərmək üçün ekranın sərhədində alternativ qırmızı və mavi çubuqları göstərir. Pilot tonu bitir sinxron nəbz, kompüterə məlumat qəbul etməyə başlamaq üçün siqnal verir. Daha qısa müddət (pilot tonu və sonrakı məlumatlar ilə müqayisədə) ilə xarakterizə olunur (şəklə bax)

Sinxronizasiya impulsu qəbul edildikdən sonra kompüter siqnalın hər bir yüksəlişini/düşməsini qeyd edir, müddətini ölçür. Müddət müəyyən limitdən azdırsa, bit 1 yaddaşa yazılır, əks halda 0. Bitlər baytlarda toplanır və N bayt alınana qədər proses təkrarlanır. N sayı adətən yüklənmiş faylın başlığından götürülür. Yükləmə ardıcıllığı aşağıdakı kimidir:

  1. pilot tonu
  2. başlıq (sabit uzunluq), yüklənmiş məlumatın ölçüsünü (N), fayl adını və növünü ehtiva edir
  3. pilot tonu
  4. məlumatların özü

Məlumatların düzgün yükləndiyinə əmin olmaq üçün ZX Spectrum sözdə oxuyur paritet bayt (paritet baytı), yazılı məlumatların bütün baytlarını XORing etməklə faylı saxlayarkən hesablanır. Faylı oxuyarkən, kompüter alınan məlumatlardan paritet baytını hesablayır və nəticə saxlanandan fərqlidirsə, "R Tape yükləmə xətası" səhv mesajını göstərir. Düzünü desək, kompüter oxuyarkən nəbzi tanıya bilmədikdə (buraxılmış və ya onun müddəti müəyyən məhdudiyyətlərə uyğun gəlmirsə) bu mesajı daha əvvəl verə bilər.

Beləliklə, indi naməlum siqnalın necə göründüyünü görək:

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Bu pilot tondur. Siqnalın forması əhəmiyyətli dərəcədə fərqlidir, lakin aydındır ki, siqnal müəyyən tezlikdə təkrarlanan qısa impulslardan ibarətdir. 44100 Hz seçmə tezliyində “zirvələr” arasındakı məsafə təqribən 48 nümunədir (bu, ~918 Hz tezliyinə uyğundur).Gəlin bu rəqəmi xatırlayaq.

İndi məlumat fraqmentinə baxaq:

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Fərdi impulslar arasındakı məsafəni ölçsək, məlum olur ki, "uzun" impulslar arasındakı məsafə hələ də ~48 nümunə, qısa olanlar arasında isə ~24 nümunədir. Bir az irəliyə baxaraq deyim ki, sonda məlum oldu ki, 918 Hz tezliyi olan “istinad” impulsları faylın əvvəlindən sonuna qədər davamlı olaraq izləyir. Ehtimal etmək olar ki, verilənlərin ötürülməsi zamanı istinad impulsları arasında əlavə impulsla rastlaşdıqda onu bit 1, əks halda 0 hesab edirik.

Sinxronizasiya nəbzi haqqında nə demək olar? Gəlin məlumatların əvvəlinə baxaq:

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Pilot ton bitir və məlumat dərhal başlayır. Bir az sonra, bir neçə fərqli səs yazısını təhlil etdikdən sonra, məlumatın ilk baytının həmişə eyni olduğunu kəşf edə bildik (10100101b, A5h). Kompüter məlumatları qəbul etdikdən sonra oxumağa başlaya bilər.

Sinxronizasiya baytında sonuncu 1-cidən dərhal sonra ilk istinad nəbzinin yerdəyişməsinə də diqqət yetirə bilərsiniz. O, daha sonra məlumatların tanınması proqramının işlənib hazırlanması prosesində, faylın əvvəlindəki verilənləri sabit oxumaq mümkün olmadığı zaman aşkar edilmişdir.

İndi audio faylı emal edəcək və verilənləri yükləyəcək alqoritmi təsvir etməyə çalışaq.

Data Yüklənir

Əvvəlcə alqoritmi sadə saxlamaq üçün bir neçə fərziyyəyə baxaq:

  1. Biz yalnız WAV formatında olan faylları nəzərdən keçirəcəyik;
  2. Audio fayl pilot tonla başlamalı və başlanğıcda səssizliyi ehtiva etməməlidir
  3. Mənbə faylının seçmə sürəti 44100 Hz olmalıdır. Bu halda, 48 nümunənin istinad impulsları arasındakı məsafə artıq müəyyən edilmişdir və onu proqramlı şəkildə hesablamağa ehtiyac yoxdur;
  4. Nümunə formatı istənilən ola bilər (8/16 bit/üzən nöqtə) - çünki oxuyarkən onu istədiyinizə çevirə bilərik;
  5. Güman edirik ki, mənbə faylı amplituda ilə normallaşdırılıb, nəticə sabitləşməlidir;

Oxuma alqoritmi aşağıdakı kimi olacaq:

  1. Faylı yaddaşa oxuyuruq, eyni zamanda nümunə formatını 8 bitə çeviririk;
  2. Səs məlumatında ilk nəbzin yerini müəyyənləşdirin. Bunu etmək üçün nümunənin sayını maksimum amplituda ilə hesablamaq lazımdır. Sadəlik üçün onu bir dəfə əl ilə hesablayacağıq. Gəlin onu prev_pos dəyişəninə saxlayaq;
  3. Son nəbzin mövqeyinə 48 əlavə edin (pos := prev_pos + 48)
  4. Mövqeyi 48-ə artırmaq növbəti istinad nəbzinin mövqeyinə (lent qüsurları, lent ötürücü mexanizminin qeyri-sabit işləməsi və s.) Bunun üçün kiçik bir məlumat parçası götürün (pos-8;pos+8) və onun üzərindəki maksimum amplituda dəyərini tapın. Maksimuma uyğun mövqe pos-da saxlanılacaq. Burada 8 = 48/6 eksperimental olaraq əldə edilmiş sabitdir, bu, düzgün maksimumu təyin edəcəyimizə və yaxınlıqda ola biləcək digər impulslara təsir etməyəcəyimizə zəmanət verir. Çox pis hallarda, impulslar arasındakı məsafə 48-dən çox az və ya daha çox olduqda, nəbz üçün məcburi axtarış həyata keçirə bilərsiniz, lakin məqalə çərçivəsində bunu alqoritmdə təsvir etməyəcəyəm;
  5. Əvvəlki addımda, həmçinin istinad nəbzinin ümumiyyətlə tapıldığını yoxlamaq lazımdır. Yəni, sadəcə maksimumu axtarırsınızsa, bu, impulsun bu seqmentdə mövcud olduğuna zəmanət vermir. Oxuma proqramının son tətbiqində bir seqmentdə maksimum və minimum amplituda dəyərləri arasındakı fərqi yoxlayıram və müəyyən bir həddi keçərsə, bir impulsun varlığını hesablayıram. Sual həm də istinad nəbzi tapılmadıqda nə etməkdir. 2 variant var: ya məlumat bitdi və sonra səssizlik baş verir, ya da bu oxu xətası hesab edilməlidir. Bununla belə, alqoritmi sadələşdirmək üçün bunu buraxacağıq;
  6. Növbəti addımda məlumat impulsunun (bit 0 və ya 1) mövcudluğunu müəyyən etməliyik, bunun üçün seqmentin ortasını (prev_pos;pos) orta_posu orta_pos := (prev_pos+pos)/2-yə bərabər götürürük və seqmentdə orta_posun bəzi məhəlləsində (middle_pos-8;middle_pos +8) maksimum və minimum amplitudu hesablayaq. Aralarındakı fərq 10-dan çox olarsa, nəticəyə bit 1 yazırıq, əks halda 0. 10 təcrübi yolla alınan sabitdir;
  7. Cari mövqeyi əvvəlki_postda saxlayın (əvvəlki_pos := pos)
  8. 3-cü addımdan başlayaraq bütün faylı oxuyana qədər təkrarlayın;
  9. Nəticə bit massivi bayt dəsti kimi saxlanmalıdır. Oxuyarkən sinxron baytını nəzərə almadığımız üçün bitlərin sayı 8-ə çox olmaya bilər və tələb olunan bit ofset də məlum deyil. Alqoritmin ilk tətbiqində mən sinxron baytın mövcudluğu haqqında bilmirdim və buna görə də sadəcə müxtəlif sayda ofset bitləri olan 8 faylı saxladım. Onlardan birində düzgün məlumatlar var idi. Son alqoritmdə mən sadəcə A5h-ə qədər olan bütün bitləri silirəm ki, bu da mənə dərhal düzgün çıxış faylını əldə etməyə imkan verir.

Maraqlananlar üçün Ruby-də alqoritm
Proqramı yazmaq üçün Ruby dilini seçdim, çünki... Mən çox vaxt bunun üzərində proqramlaşdırıram. Seçim yüksək performanslı deyil, lakin oxu sürətini mümkün qədər sürətli etmək vəzifəsi buna dəyər deyil.

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

Nəticə

Alqoritmin və sabitlərin bir neçə variantını sınadıqdan sonra son dərəcə maraqlı bir şey əldə etmək şanslı oldum:

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Beləliklə, simvol sətirlərinə əsasən, qrafiklərin qurulması üçün bir proqramımız var. Bununla belə, proqram mətnində açar sözlər yoxdur. Bütün açar sözlər bayt kimi kodlanır (hər dəyər > 80h). İndi 80-ci illərdən hansı kompüterin bu formatda proqramları saxlaya biləcəyini öyrənməliyik.

Əslində, o, BASIC proqramına çox bənzəyir. ZX Spectrum kompüteri proqramları təxminən eyni formatda yaddaşda saxlayır və proqramları lentə saxlayır. Hər ehtimala qarşı açar sözləri yoxladım masa. Ancaq nəticə açıq-aydın mənfi idi.

Mən də o dövrün məşhur Atari, Commodore 64 və bir neçə digər kompüterlərin BASIC açar sözlərini yoxladım, bunun üçün sənədləri tapa bildim, lakin uğur qazana bilmədim - retro kompüterlərin növləri haqqında biliklərim o qədər də geniş olmadığı ortaya çıxdı.

Sonra getməyə qərar verdim siyahı, və sonra baxışlarım istehsalçı Radio Shack və TRS-80 kompüterinin adına düşdü. Masamın üstündə uzanan kasetlərin etiketlərində belə adlar yazılmışdı! Mən əvvəllər bu adları bilmirdim və TRS-80 kompüteri ilə tanış deyildim, ona görə də mənə elə gəldi ki, Radio Shack BASF, Sony və ya TDK kimi audio kaset istehsalçısıdır, TRS-80 isə çalma vaxtıdır. Niyə də yox?

Kompüter Tandy/Radio Shack TRS-80

Çox güman ki, məqalənin əvvəlində misal gətirdiyim sözügedən səs yazısı belə bir kompüterdə hazırlanıb:

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

Məlum oldu ki, bu kompüter və onun növləri (Model I/Model III/Model IV və s.) bir vaxtlar çox məşhur idi (əlbəttə, Rusiyada deyil). İstifadə etdikləri prosessorun da Z80 olması diqqət çəkir. Bu kompüter üçün İnternetdə tapa bilərsiniz çoxlu məlumat. 80-ci illərdə kompüter məlumatları yayılmışdır jurnallar. Hal-hazırda bir neçə var emulyatorlar müxtəlif platformalar üçün kompüterlər.

Emulatoru yüklədim trs80gp və ilk dəfə bu kompüterin necə işlədiyini görə bildim. Əlbəttə ki, kompüter rəng çıxışını dəstəkləmirdi, ekran həlli yalnız 128x48 piksel idi, lakin ekranın təsvir ölçüsünü artıra biləcək bir çox genişləndirmə və modifikasiya var idi. Bu kompüter üçün əməliyyat sistemləri üçün çoxlu seçimlər və BASIC dilinin tətbiqi variantları da var idi (bu, ZX Spectrum-dan fərqli olaraq, bəzi modellərdə hətta ROM-a “yandırılmayıb” və istənilən seçim disketdən yüklənə bilərdi. OS özü)

mən də tapdım kommunal səs yazılarını emulyatorlar tərəfindən dəstəklənən CAS formatına çevirmək, lakin nədənsə onlardan istifadə edərək kasetlərimdən yazıları oxumaq mümkün olmadı.

CAS fayl formatını (bu, sinxron baytın mövcudluğu ilə başlıq istisna olmaqla, əlimdə olan məlumatların sadəcə bir bit-bit nüsxəsi olduğu ortaya çıxdı) anladım. proqramıma bir neçə dəyişiklik etdi və emulyatorda işləyən işləyən CAS faylını çıxara bildim (TRS-80 Model III):

Mən maqnit lentindən naməlum formatda məlumatları necə bərpa etdim

GEM paketi olaraq ilk nəbzin və istinad impulsları arasındakı məsafənin avtomatik müəyyən edilməsi ilə dönüşüm yardım proqramının ən son versiyasını tərtib etdim, mənbə kodu burada mövcuddur. Github.

Nəticə

Keçdiyimiz yol keçmişə maraqlı səyahət oldu və mən şadam ki, sonunda cavabı tapdım. Digər şeylər arasında mən:

  • Mən ZX Spectrum-da məlumatların saxlanması formatını tapdım və audio kasetlərdən məlumatların saxlanması/oxuması üçün daxili ROM qaydalarını öyrəndim.
  • TRS-80 kompüteri və onun növləri ilə tanış oldum, əməliyyat sistemini öyrəndim, nümunə proqramlara baxdım və hətta maşın kodlarında sazlama etmək imkanım oldu (axı bütün Z80 mnemonikaları mənə tanışdır)
  • Səs yazılarını CAS formatına çevirmək üçün "rəsmi" yardım proqramı tərəfindən tanınmayan məlumatları oxuya bilən tam hüquqlu bir yardım proqramı yazdı.

Mənbə: www.habr.com

Добавить комментарий