prasejarah
Dadi pacangan hardware retro, aku tau tuku ZX Spectrum + saka bakul ing UK. Kalebu karo komputer dhewe, aku nampa sawetara kaset audio karo game (ing kemasan asli karo instruksi), uga program sing direkam ing kaset tanpa tandha khusus. Kaget, data saka kaset 40 taun bisa diwaca kanthi apik lan aku bisa ndownload meh kabeh game lan program saka dheweke.
Nanging, ing sawetara kaset aku nemokake rekaman sing jelas ora digawe dening komputer ZX Spectrum. Padha muni temen beda lan, ora kaya rekaman saka komputer kasebut, padha ora miwiti karo bootloader BASIC singkat, kang biasane ana ing rekaman kabeh program lan game.
Kanggo sawetara wektu iki Angker kula - Aku pancene wanted kanggo mangerteni apa sing didhelikake ing wong. Yen sampeyan bisa maca sinyal audio minangka urutan bita, sampeyan bisa nggoleki karakter utawa apa wae sing nuduhake asal saka sinyal kasebut. A jinis retro-arkeologi.
Saiki aku wis lunga kabeh lan ndeleng label saka kaset dhewe, aku mesem amarga
wangsulane ana ing ngarep mripatku kabeh
Ing label kaset kiwa ana jeneng komputer TRS-80, lan ing ngisor jeneng pabrikan: "Diprodhuksi dening Radio Shack ing AS"
(Yen sampeyan pengin tetep intrik nganti pungkasan, aja nganti spoiler)
Perbandingan sinyal audio
Kaping pisanan, ayo digitalisasi rekaman audio. Sampeyan bisa ngrungokake kaya apa:
Lan kaya biasane, rekaman saka komputer ZX Spectrum muni:
Ing kasus loro, ing awal rekaman ana sing disebut nada pilot - swara kanthi frekuensi sing padha (ing rekaman pisanan cendhak banget <1 detik, nanging bisa dibedakake). Nada pilot menehi sinyal komputer kanggo nyiapake nampa data. Minangka aturan, saben komputer mung ngenali nada pilot "dhewe" kanthi bentuk sinyal lan frekuensi.
Sampeyan perlu kanggo ngomong soko bab wangun sinyal dhewe. Contone, ing ZX Spectrum wangunΓ© persegi dowo:
Nalika nada pilot dideteksi, ZX Spectrum nampilake bar abang lan biru gantian ing tapel wates layar kanggo nuduhake yen sinyal wis dikenali. Nada pilot rampung pulsa sinkro, sing menehi sinyal komputer kanggo miwiti nampa data. Iki ditondoi kanthi durasi sing luwih cendhek (dibandhingake karo nada pilot lan data sabanjure) (pirsani gambar)
Sawise pulsa sinkronisasi ditampa, komputer nyathet saben munggah / mudhun sinyal, ngukur durasi. Yen durasi kurang saka watesan tartamtu, bit 1 ditulis ing memori, yen ora 0. Bit diklumpukake dadi bita lan proses kasebut diulang nganti N bita ditampa. Nomer N biasane dijupuk saka header file sing diundhuh. Urutan loading kaya ing ngisor iki:
- nada pilot
- header (dawa tetep), ngemot ukuran data sing diundhuh (N), jeneng file lan jinis
- nada pilot
- data dhewe
Kanggo mesthekake yen data dimuat kanthi bener, maca ZX Spectrum sing diarani bait paritas (bait paritas), sing diwilang nalika nyimpen file kanthi XORing kabeh bita saka data sing ditulis. Nalika maca file, komputer ngetung bait paritas saka data sing ditampa lan, yen asil beda karo sing disimpen, nampilake pesen kesalahan "R Tape loading error". Tegese, komputer bisa ngetokake pesen iki luwih dhisik yen, nalika maca, ora bisa ngenali pulsa (ora kejawab utawa durasine ora cocog karo watesan tartamtu)
Dadi, ayo ndeleng apa sinyal sing ora dingerteni:
Iki minangka nada pilot. Bentuk sinyal kasebut beda banget, nanging jelas yen sinyal kasebut kalebu mbaleni pulsa cendhak frekuensi tartamtu. Ing frekuensi sampling 44100 Hz, jarak antarane "puncak" kira-kira 48 conto (sing cocog karo frekuensi ~ 918 Hz). Ayo elinga tokoh iki.
Ayo saiki ndeleng fragmen data:
Yen kita ngukur jarak antarane pulsa individu, ternyata jarak antarane pulsa "dawa" isih ~ 48 sampel, lan antarane sing cendhak - ~ 24. Looking ahead sethitik, Aku bakal ngomong sing ing pungkasan iku nguripake metu sing "referensi" pulses karo frekuensi 918 Hz tindakake terus-terusan, saka awal kanggo mburi file. Bisa dianggep yen nalika ngirim data, yen ana pulsa tambahan ing antarane pulsa referensi, kita nganggep minangka bit 1, yen ora 0.
Kepiye babagan pulsa sinkronisasi? Ayo katon ing wiwitan data:
Nada pilot rampung lan data diwiwiti langsung. Ora suwe, sawise nganalisa sawetara rekaman audio sing beda-beda, kita bisa nemokake manawa data byte pisanan mesthi padha (10100101b, A5h). Komputer bisa miwiti maca data sawise nampa.
Sampeyan uga bisa mbayar manungsa waΓ© menyang shift pulsa referensi pisanan sanalika sawise 1st pungkasan ing bait sinkronisasi. Ditemokake mengko ing proses ngembangake program pangenalan data, nalika data ing wiwitan file ora bisa dibaca kanthi stabil.
Saiki ayo nyoba njlèntrèhaké algoritma sing bakal ngolah file audio lan mbukak data.
Loading Data
Pisanan, ayo goleki sawetara asumsi supaya algoritma tetep prasaja:
- Kita mung bakal nimbang file ing format WAV;
- File audio kudu diwiwiti kanthi nada pilot lan ora kudu nggawe bisu ing wiwitan
- File sumber kudu duwe tingkat sampling 44100 Hz. Ing kasus iki, jarak antarane pulsa referensi saka 48 sampel wis ditemtokake lan kita ora perlu ngetung kanthi program;
- Format sampel bisa wae (8/16 bit / floating point) - amarga nalika maca, kita bisa ngowahi menyang sing dikarepake;
- Kita nganggep yen file sumber dinormalisasi kanthi amplitudo, sing kudu nyetabilake asil;
Algoritma maca bakal kaya ing ngisor iki:
- Kita maca file menyang memori, ing wektu sing padha ngowahi format sampel dadi 8 bit;
- Nemtokake posisi pulsa pisanan ing data audio. Kanggo nindakake iki, sampeyan kudu ngetung jumlah sampel kanthi amplitudo maksimum. Kanggo gamblang, kita bakal ngetung sapisan kanthi manual. Ayo disimpen menyang variabel prev_pos;
- Tambah 48 menyang posisi pulsa pungkasan (pos := prev_pos + 48)
- Wiwit nambah posisi kanthi 48 ora njamin yen kita bakal entuk posisi pulsa referensi sabanjure (cacat tape, operasi mekanisme tape drive sing ora stabil, lan liya-liyane), kita kudu nyetel posisi pos pulsa. Kanggo nindakake iki, njupuk bagéyan cilik saka data (pos-8; pos + 8) lan golek nilai amplitudo maksimum ing. Posisi sing cocog karo maksimal bakal disimpen ing pos. Ing kene 8 = 48/6 minangka konstanta sing diduweni kanthi eksperimen, sing njamin kita bakal nemtokake maksimum sing bener lan ora bakal mengaruhi impuls liyane sing bisa uga ana ing cedhak. Ing kasus sing ala banget, nalika jarak antarane pulsa kurang saka utawa luwih saka 48, sampeyan bisa ngleksanakake telusuran paksa kanggo pulsa, nanging ing ruang lingkup artikel aku ora bakal njlèntrèhaké iki ing algoritma;
- Ing langkah sadurunge, sampeyan uga kudu mriksa manawa pulsa referensi ditemokake. Yaiku, yen sampeyan mung nggoleki maksimal, iki ora njamin yen impuls ana ing segmen iki. Ing implementasine program maca paling anyar, aku mriksa prabΓ©dan antarane nilai amplitudo maksimum lan minimal ing sawijining segmen, lan yen ngluwihi watesan tartamtu, aku ngetung ananΓ© impuls. Pitakonan uga apa sing kudu ditindakake yen pulsa referensi ora ditemokake. Ana 2 opsi: salah siji data wis rampung lan kasepen nderek, utawa iki kudu dianggep minangka kesalahan maca. Nanging, kita bakal ngilangi iki kanggo nyederhanakake algoritma;
- Ing langkah sabanjure, kita kudu nemtokake ananΓ© pulsa data (bit 0 utawa 1), kanggo iki kita njupuk tengah segmen (prev_pos;pos) middle_pos padha karo middle_pos := (prev_pos+pos)/2 lan ing sawetara lingkungan middle_pos ing babagan (middle_pos-8;middle_pos +8) ayo ngetung amplitudo maksimum lan minimal. Yen prabΓ©dan antarane wong-wong mau luwih saka 10, kita nulis bit 1 menyang asil, digunakake 0. 10 punika pancet dijupuk eksperimen;
- Simpen posisi saiki ing prev_pos (prev_pos := pos)
- Baleni wiwit saka langkah 3 nganti kita maca kabeh file;
- Array bit sing diasilake kudu disimpen minangka set bita. Awit kita ora njupuk menyang akun bait sinkronisasi nalika maca, jumlah bit bisa uga ora kaping 8, lan bit sing dibutuhake uga ora dingerteni. Ing implementasine algoritma pisanan, aku ora ngerti babagan anane bait sinkronisasi lan mulane mung nyimpen 8 file kanthi jumlah bit offset sing beda. Salah sijine ngemot data sing bener. Ing algoritma pungkasan, aku mung mbusak kabeh bit nganti A5h, sing ngidini aku langsung entuk file output sing bener
Algoritma ing Ruby, kanggo sing kasengsem
Aku milih Ruby minangka basa kanggo nulis program, amarga ... Aku program ing paling wektu. Opsi kasebut ora nduweni kinerja dhuwur, nanging tugas kanggo nggawe kacepetan maca kanthi cepet ora pantes.
# ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ 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*")
asil
Sawise nyoba sawetara varian saka algoritma lan konstanta, aku begja entuk sing menarik banget:
Dadi, miturut senar karakter, kita duwe program kanggo ngrancang grafik. Nanging, ora ana tembung kunci ing teks program. Kabeh tembung kunci dienkode minangka bita (saben nilai> 80h). Saiki kita kudu ngerti komputer saka 80s bisa nyimpen program ing format iki.
Nyatane, meh padha karo program BASIC. Komputer ZX Spectrum nyimpen program ing format sing padha ing memori lan nyimpen program kanggo tape. Ing kasus, aku mriksa tembung kunci marang
Aku uga mriksa tembung kunci BASIC saka Atari populer, Commodore 64 lan sawetara komputer liyane ing wektu iku, sing aku bisa nemokake dokumentasi, nanging tanpa sukses - kawruh saka jinis komputer retro dadi ora amba.
Banjur aku mutusake lunga
Komputer Tandy/Radio Shack TRS-80
Kemungkinan rekaman audio kasebut, sing dakwenehake minangka conto ing wiwitan artikel, digawe ing komputer kaya mangkene:
Ternyata komputer iki lan macem-macem (Model I / Model III / Model IV, lan sapiturute) banget populer ing sawijining wektu (mesthi, ora ing Rusia). Wigati dimangerteni manawa prosesor sing digunakake uga Z80. Kanggo komputer iki sampeyan bisa nemokake ing Internet
Aku ngundhuh emulator
Aku uga ketemu
Sawise ngerteni format file CAS (sing dadi salinan data saka tape sing wis ana, kajaba header sing ana bait sinkronisasi), aku nggawe sawetara owah-owahan ing programku lan bisa ngasilake file CAS sing bisa digunakake ing emulator (TRS-80 Model III):
Aku ngrancang versi paling anyar saka sarana konversi kanthi otomatis nemtokake pulsa pisanan lan jarak antarane pulsa referensi minangka paket GEM, kode sumber kasedhiya ing
kesimpulan
Dalan sing wis kita lewati dadi perjalanan sing nyenengake ing jaman kepungkur, lan aku bungah yen pungkasane aku nemokake jawaban kasebut. Antarane liyane, aku:
- Aku ngerteni format kanggo nyimpen data ing ZX Spectrum lan sinau rutin ROM sing dibangun kanggo nyimpen / maca data saka kaset audio
- Aku kenal karo komputer TRS-80 lan macem-macem, sinau sistem operasi, ndeleng program sampel lan malah duwe kesempatan kanggo debugging ing kode mesin (sawise kabeh, kabeh mnemonik Z80 wis kenal karo aku).
- Nulis sarana lengkap kanggo ngowahi rekaman audio menyang format CAS, sing bisa maca data sing ora diakoni dening sarana "resmi".
Source: www.habr.com