Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

prasejarah

Sebagai pecinta hardware retro, saya pernah membeli ZX Spectrum+ dari penjual di Inggris. Termasuk dengan komputer itu sendiri, saya menerima beberapa kaset audio berisi permainan (dalam kemasan aslinya dengan instruksi), serta program yang direkam pada kaset tanpa tanda khusus. Anehnya, data dari kaset berusia 40 tahun dapat dibaca dengan baik dan saya dapat mengunduh hampir semua permainan dan program dari kaset tersebut.

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Namun pada beberapa kaset saya menemukan rekaman yang jelas-jelas tidak dibuat oleh komputer ZX Spectrum. Kedengarannya sangat berbeda dan, tidak seperti rekaman dari komputer yang disebutkan, rekaman tersebut tidak dimulai dengan bootloader BASIC pendek, yang biasanya ada dalam rekaman semua program dan permainan.

Untuk beberapa waktu hal ini menghantui saya - saya benar-benar ingin mencari tahu apa yang tersembunyi di dalamnya. Jika Anda dapat membaca sinyal audio sebagai rangkaian byte, Anda dapat mencari karakter atau apa pun yang menunjukkan asal sinyal. Semacam retro-arkeologi.

Sekarang setelah saya melihat-lihat label kaset itu sendiri, saya tersenyum karenanya

jawabannya tepat di depan mataku selama ini
Pada label kaset kiri terdapat nama komputer TRS-80, dan tepat di bawah nama pabrikan: β€œDiproduksi oleh Radio Shack di AS”

(Jika Anda ingin mempertahankan intrik sampai akhir, jangan ikuti spoiler)

Perbandingan sinyal audio

Pertama-tama, mari kita digitalkan rekaman audio. Anda dapat mendengarkan seperti apa suaranya:


Dan seperti biasa rekaman dari komputer ZX Spectrum berbunyi :


Dalam kedua kasus tersebut, di awal rekaman ada yang disebut nada percontohan - suara dengan frekuensi yang sama (pada rekaman pertama sangat pendek <1 detik, tetapi dapat dibedakan). Nada pilot memberi sinyal pada komputer untuk bersiap menerima data. Biasanya, setiap komputer hanya mengenali nada pilot β€œsendiri” berdasarkan bentuk sinyal dan frekuensinya.

Penting untuk mengatakan sesuatu tentang bentuk sinyal itu sendiri. Misalnya pada ZX Spectrum bentuknya persegi panjang:

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Ketika nada pilot terdeteksi, ZX Spectrum menampilkan bilah merah dan biru bergantian di tepi layar untuk menunjukkan bahwa sinyal telah dikenali. Nada percontohan berakhir pulsa sinkronisasi, yang memberi sinyal kepada komputer untuk mulai menerima data. Hal ini ditandai dengan durasi yang lebih pendek (dibandingkan dengan nada pilot dan data selanjutnya) (lihat gambar)

Setelah pulsa sinkronisasi diterima, komputer mencatat setiap naik/turunnya sinyal, mengukur durasinya. Jika durasinya kurang dari batas tertentu, bit 1 ditulis ke memori, sebaliknya 0. Bit dikumpulkan menjadi byte dan proses diulangi hingga diterima N byte. Angka N biasanya diambil dari header file yang diunduh. Urutan pemuatannya adalah sebagai berikut:

  1. nada percontohan
  2. header (panjang tetap), berisi ukuran data yang diunduh (N), nama dan jenis file
  3. nada percontohan
  4. data itu sendiri

Untuk memastikan bahwa data dimuat dengan benar, ZX Spectrum membaca apa yang disebut paritas byte (paritas byte), yang dihitung saat menyimpan file dengan meng-XOR semua byte data tertulis. Saat membaca file, komputer menghitung byte paritas dari data yang diterima dan, jika hasilnya berbeda dari yang disimpan, komputer menampilkan pesan kesalahan "R Tape memuat kesalahan". Sebenarnya, komputer dapat mengeluarkan pesan ini lebih awal jika, saat membaca, ia tidak dapat mengenali pulsa (tidak terjawab atau durasinya tidak sesuai dengan batas tertentu)

Jadi, sekarang mari kita lihat seperti apa sinyal yang tidak diketahui itu:

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Ini adalah nada percontohan. Bentuk sinyalnya sangat berbeda, tetapi jelas bahwa sinyal tersebut terdiri dari pulsa-pulsa pendek yang berulang dengan frekuensi tertentu. Pada frekuensi sampling 44100 Hz, jarak antara β€œpuncak” adalah sekitar 48 sampel (yang setara dengan frekuensi ~918 Hz). Mari kita ingat angka ini.

Sekarang mari kita lihat bagian datanya:

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Jika kita mengukur jarak antar pulsa, ternyata jarak antar pulsa β€œpanjang” masih ~48 sampel, dan antara pulsa pendek – ~24. Sedikit ke depan, saya akan mengatakan bahwa pada akhirnya ternyata pulsa β€œreferensi” dengan frekuensi 918 Hz mengikuti terus menerus, dari awal hingga akhir file. Dapat diasumsikan bahwa ketika mentransmisikan data, jika ada pulsa tambahan di antara pulsa referensi, kami menganggapnya sebagai bit 1, jika tidak 0.

Bagaimana dengan pulsa sinkronisasi? Mari kita lihat data awal:

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Nada pilot berakhir dan data segera dimulai. Beberapa saat kemudian, setelah menganalisis beberapa rekaman audio yang berbeda, kami menemukan bahwa byte pertama data selalu sama (10100101b, A5h). Komputer mungkin mulai membaca data setelah menerimanya.

Anda juga dapat memperhatikan pergeseran pulsa referensi pertama segera setelah pulsa pertama terakhir dalam byte sinkronisasi. Hal ini ditemukan kemudian dalam proses pengembangan program pengenalan data, ketika data di awal file tidak dapat dibaca secara stabil.

Sekarang mari kita coba menjelaskan algoritma yang akan memproses file audio dan memuat data.

Memuat Data

Pertama, mari kita lihat beberapa asumsi untuk menjaga algoritma tetap sederhana:

  1. Kami hanya akan mempertimbangkan file dalam format WAV;
  2. File audio harus dimulai dengan nada pilot dan tidak boleh berisi keheningan di awal
  3. File sumber harus memiliki laju pengambilan sampel 44100 Hz. Dalam hal ini, jarak antara pulsa referensi dari 48 sampel sudah ditentukan dan kita tidak perlu menghitungnya secara terprogram;
  4. Format sampelnya bisa apa saja (8/16 bit/floating point) - karena saat membaca kita dapat mengonversinya ke format yang diinginkan;
  5. Kami berasumsi bahwa file sumber dinormalisasi berdasarkan amplitudo, yang seharusnya menstabilkan hasilnya;

Algoritma pembacaannya adalah sebagai berikut:

  1. Kami membaca file ke dalam memori, sekaligus mengubah format sampel menjadi 8 bit;
  2. Tentukan posisi pulsa pertama pada data audio. Untuk melakukan ini, Anda perlu menghitung jumlah sampel dengan amplitudo maksimum. Untuk mempermudah, kami akan menghitungnya sekali secara manual. Mari kita simpan ke variabel prev_pos;
  3. Tambahkan 48 pada posisi pulsa terakhir (pos := prev_pos + 48)
  4. Karena menaikkan posisi sebesar 48 tidak menjamin kita akan mendapatkan posisi pulsa referensi berikutnya (cacat pita, pengoperasian mekanisme tape drive yang tidak stabil, dll.), kita perlu menyesuaikan posisi pos pulsa. Untuk melakukan ini, ambil sebagian kecil data (pos-8;pos+8) dan temukan nilai amplitudo maksimumnya. Posisi yang sesuai dengan maksimum akan disimpan di pos. Di sini 8 = 48/6 adalah konstanta yang diperoleh secara eksperimental, yang menjamin bahwa kita akan menentukan maksimum yang benar dan tidak akan mempengaruhi impuls lain yang mungkin berada di dekatnya. Dalam kasus yang sangat buruk, ketika jarak antar pulsa jauh lebih kecil atau lebih besar dari 48, Anda dapat menerapkan pencarian paksa untuk pulsa, tetapi dalam cakupan artikel saya tidak akan menjelaskan hal ini dalam algoritme;
  5. Pada langkah sebelumnya, kita juga perlu memeriksa apakah pulsa referensi sudah ditemukan. Artinya, jika sekadar mencari maksimal, belum tentu impuls hadir di segmen tersebut. Dalam implementasi program membaca terbaru saya, saya memeriksa perbedaan antara nilai amplitudo maksimum dan minimum pada suatu segmen, dan jika melebihi batas tertentu, saya menghitung adanya impuls. Pertanyaannya juga apa yang harus dilakukan jika pulsa referensi tidak ditemukan. Ada 2 pilihan: data telah berakhir dan diikuti keheningan, atau ini harus dianggap sebagai kesalahan pembacaan. Namun, kami akan menghilangkan ini untuk menyederhanakan algoritma;
  6. Langkah selanjutnya kita perlu menentukan keberadaan pulsa data (bit 0 atau 1), untuk ini kita ambil bagian tengah segmen (prev_pos;pos) middle_pos sama dengan middle_pos := (prev_pos+pos)/2 dan di beberapa lingkungan middle_pos pada segmen (middle_pos-8;middle_pos +8) mari kita hitung amplitudo maksimum dan minimum. Jika perbedaan di antara keduanya lebih dari 10, kita menulis bit 1 ke dalam hasilnya, jika tidak, 0. 10 adalah konstanta yang diperoleh secara eksperimental;
  7. Simpan posisi saat ini di prev_pos (prev_pos := pos)
  8. Ulangi mulai dari langkah 3 hingga kita membaca keseluruhan file;
  9. Bit array yang dihasilkan harus disimpan sebagai sekumpulan byte. Karena kami tidak memperhitungkan byte sinkronisasi saat membaca, jumlah bit mungkin bukan kelipatan 8, dan offset bit yang diperlukan juga tidak diketahui. Pada implementasi pertama algoritma, saya tidak mengetahui keberadaan byte sinkronisasi dan oleh karena itu hanya menyimpan 8 file dengan jumlah bit offset yang berbeda. Salah satunya berisi data yang benar. Pada algoritme terakhir, saya cukup menghapus semua bit hingga A5h, yang memungkinkan saya segera mendapatkan file keluaran yang benar

Algoritma di Ruby, bagi yang berminat
Saya memilih Ruby sebagai bahasa untuk menulis program, karena... Saya memprogramnya hampir sepanjang waktu. Opsi ini tidak berperforma tinggi, tetapi tugas membuat kecepatan membaca secepat mungkin tidak sepadan.

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

Hasil

Setelah mencoba beberapa varian algoritma dan konstanta, saya beruntung mendapatkan sesuatu yang sangat menarik:

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Jadi, dilihat dari string karakternya, kami memiliki program untuk membuat grafik. Namun, tidak ada kata kunci dalam teks program. Semua kata kunci dikodekan sebagai byte (setiap nilai > 80 jam). Sekarang kita perlu mencari tahu komputer mana dari tahun 80an yang dapat menyimpan program dalam format ini.

Faktanya, ini sangat mirip dengan program BASIC. Komputer ZX Spectrum menyimpan program dalam format yang kira-kira sama di memori dan menyimpan program ke tape. Untuk berjaga-jaga, saya memeriksa kata kuncinya meja. Namun, hasilnya jelas negatif.

Saya juga memeriksa kata kunci BASIC dari Atari, Commodore 64 dan beberapa komputer lain yang populer pada waktu itu, yang dokumentasinya dapat saya temukan, tetapi tidak berhasil - pengetahuan saya tentang jenis-jenis komputer retro ternyata tidak begitu luas.

Lalu saya memutuskan untuk pergi Daftar, lalu pandangan saya tertuju pada nama pabrikan Radio Shack dan komputer TRS-80. Inilah nama-nama yang tertulis pada label kaset yang tergeletak di meja saya! Saya tidak mengetahui nama-nama ini sebelumnya dan tidak mengenal komputer TRS-80, jadi menurut saya Radio Shack adalah produsen kaset audio seperti BASF, Sony atau TDK, dan TRS-80 adalah waktu pemutarannya. Mengapa tidak?

Komputer Tandy/Radio Shack TRS-80

Kemungkinan besar rekaman audio yang dimaksud, yang saya berikan sebagai contoh di awal artikel, dibuat di komputer seperti ini:

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Ternyata komputer ini dan variannya (Model I/Model III/Model IV, dll.) pernah sangat populer (tentu saja, bukan di Rusia). Patut dicatat bahwa prosesor yang mereka gunakan juga Z80. Untuk komputer ini Anda dapat menemukannya di Internet Banyak informasi. Pada tahun 80an, informasi komputer didistribusikan majalah. Saat ini ada beberapa emulator komputer untuk platform yang berbeda.

Saya mengunduh emulatornya trs80gp dan untuk pertama kalinya saya bisa melihat cara kerja komputer ini. Tentu saja komputer tidak mendukung keluaran warna, resolusi layar hanya 128x48 piksel, namun banyak ekstensi dan modifikasi yang dapat meningkatkan resolusi layar. Ada juga banyak pilihan sistem operasi untuk komputer ini dan pilihan untuk mengimplementasikan bahasa BASIC (yang, tidak seperti ZX Spectrum, dalam beberapa model bahkan tidak "di-flash" ke ROM dan opsi apa pun dapat dimuat dari floppy disk, seperti OS itu sendiri)

Saya juga menemukan utilitas untuk mengonversi rekaman audio ke format CAS, yang didukung oleh emulator, tetapi karena alasan tertentu tidak mungkin membaca rekaman dari kaset saya dengan menggunakannya.

Setelah mengetahui format file CAS (yang ternyata hanya salinan sedikit demi sedikit dari data dari kaset yang sudah saya miliki, kecuali header dengan adanya byte sinkronisasi), saya membuat beberapa perubahan pada program saya dan dapat menghasilkan file CAS yang berfungsi di emulator (TRS-80 Model III):

Bagaimana saya memulihkan data dalam format yang tidak diketahui dari pita magnetik

Saya merancang versi terbaru dari utilitas konversi dengan penentuan otomatis pulsa pertama dan jarak antara pulsa referensi sebagai paket GEM, kode sumber tersedia di Github.

Kesimpulan

Jalan yang kami lalui ternyata merupakan perjalanan yang menakjubkan ke masa lalu, dan saya senang pada akhirnya menemukan jawabannya. Antara lain, saya:

  • Saya menemukan format untuk menyimpan data di ZX Spectrum dan mempelajari rutinitas ROM bawaan untuk menyimpan/membaca data dari kaset audio
  • Saya mengenal komputer TRS-80 dan variasinya, mempelajari sistem operasi, melihat contoh program dan bahkan berkesempatan untuk melakukan debugging pada kode mesin (bagaimanapun juga, semua mnemonik Z80 sudah tidak asing lagi bagi saya)
  • Menulis utilitas lengkap untuk mengonversi rekaman audio ke format CAS, yang dapat membaca data yang tidak dikenali oleh utilitas "resmi"

Sumber: www.habr.com

Tambah komentar