Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

kabla ya historia

Kwa kuwa mpenzi wa maunzi ya retro, niliwahi kununua ZX Spectrum+ kutoka kwa muuzaji nchini Uingereza. Imejumuishwa na kompyuta yenyewe, nilipokea kaseti kadhaa za sauti na michezo (katika kifurushi cha asili kilicho na maagizo), pamoja na programu zilizorekodiwa kwenye kaseti bila alama maalum. Kwa kushangaza, data kutoka kwa kaseti za umri wa miaka 40 zilisomeka vizuri na niliweza kupakua karibu michezo na programu zote kutoka kwao.

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Walakini, kwenye kaseti zingine nilipata rekodi ambazo hazikutengenezwa na kompyuta ya ZX Spectrum. Walisikika tofauti kabisa na, tofauti na rekodi kutoka kwa kompyuta iliyotajwa, hawakuanza na bootloader fupi ya BASIC, ambayo kwa kawaida iko kwenye rekodi za programu na michezo yote.

Kwa muda hii ilinisumbua - nilitaka sana kujua ni nini kilifichwa ndani yao. Ikiwa ungeweza kusoma mawimbi ya sauti kama mlolongo wa baiti, unaweza kutafuta herufi au kitu chochote kinachoonyesha asili ya mawimbi. Aina ya akiolojia ya retro.

Sasa kwa kuwa nimeenda kabisa na kuangalia lebo za kaseti zenyewe, ninatabasamu kwa sababu

jibu lilikuwa mbele ya macho yangu muda wote
Kwenye lebo ya kaseti ya kushoto kuna jina la kompyuta ya TRS-80, na chini kidogo ya jina la mtengenezaji: "Imetengenezwa na Radio Shack nchini Marekani"

(Ikiwa unataka kuweka fitina hadi mwisho, usiende chini ya mharibifu)

Ulinganisho wa ishara za sauti

Kwanza kabisa, hebu tubadilishe rekodi za sauti kwenye dijitali. Unaweza kusikiliza jinsi inavyosikika:


Na kama kawaida rekodi kutoka kwa kompyuta ya ZX Spectrum inasikika:


Katika matukio yote mawili, mwanzoni mwa kurekodi kuna kinachojulikana sauti ya majaribio - sauti ya mzunguko sawa (katika kurekodi kwanza ni mfupi sana <sekunde 1, lakini inaweza kutofautishwa). Toni ya majaribio inaashiria kompyuta kujiandaa kupokea data. Kama sheria, kila kompyuta inatambua tu sauti yake ya majaribio "mwenyewe" kwa sura ya ishara na mzunguko wake.

Ni muhimu kusema kitu kuhusu sura ya ishara yenyewe. Kwa mfano, kwenye Spectrum ya ZX umbo lake ni la mstatili:

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Toni ya majaribio inapogunduliwa, ZX Spectrum huonyesha pau nyekundu na bluu zinazopishana kwenye mpaka wa skrini ili kuonyesha kuwa mawimbi yametambuliwa. Toni ya majaribio inaisha mapigo ya synchro, ambayo huashiria kompyuta kuanza kupokea data. Inajulikana kwa muda mfupi (ikilinganishwa na sauti ya majaribio na data inayofuata) (angalia takwimu)

Baada ya mapigo ya kusawazisha kupokelewa, kompyuta inarekodi kila kupanda/kushuka kwa ishara, ikipima muda wake. Ikiwa muda ni chini ya kikomo fulani, bit 1 imeandikwa kwa kumbukumbu, vinginevyo 0. Biti hukusanywa kwenye bytes na mchakato unarudiwa hadi N bytes zipokewe. Nambari N kawaida huchukuliwa kutoka kwa kichwa cha faili iliyopakuliwa. Mlolongo wa upakiaji ni kama ifuatavyo:

  1. sauti ya majaribio
  2. kichwa (urefu usiobadilika), kina ukubwa wa data iliyopakuliwa (N), jina la faili na aina
  3. sauti ya majaribio
  4. data yenyewe

Ili kuhakikisha kuwa data imepakiwa kwa usahihi, Spectrum ya ZX inasoma kinachojulikana usawa baiti (parity byte), ambayo huhesabiwa wakati wa kuhifadhi faili kwa XORing byte zote za data iliyoandikwa. Wakati wa kusoma faili, kompyuta huhesabu byte ya usawa kutoka kwa data iliyopokelewa na, ikiwa matokeo yanatofautiana na yaliyohifadhiwa, huonyesha ujumbe wa kosa "Hitilafu ya upakiaji wa Tape ya R". Kwa kusema kabisa, kompyuta inaweza kutoa ujumbe huu mapema ikiwa, wakati wa kusoma, haiwezi kutambua pigo (imekosa au muda wake haufanani na mipaka fulani)

Kwa hivyo, hebu sasa tuone jinsi ishara isiyojulikana inaonekana kama:

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Hii ni sauti ya majaribio. Sura ya ishara ni tofauti sana, lakini ni wazi kuwa ishara hiyo inajumuisha kurudia mapigo mafupi ya mzunguko fulani. Katika mzunguko wa sampuli ya 44100 Hz, umbali kati ya "kilele" ni takriban sampuli 48 (ambazo zinalingana na mzunguko wa ~ 918 Hz). Hebu tukumbuke takwimu hii.

Wacha sasa tuangalie kipande cha data:

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Ikiwa tunapima umbali kati ya mipigo ya mtu binafsi, inabadilika kuwa umbali kati ya mipigo "ndefu" bado ni ~ sampuli 48, na kati ya fupi - ~ 24. Kuangalia mbele kidogo, nitasema kwamba mwishowe ikawa kwamba mapigo ya "rejea" yenye mzunguko wa 918 Hz yanafuata mfululizo, tangu mwanzo hadi mwisho wa faili. Inaweza kuzingatiwa kuwa wakati wa kusambaza data, ikiwa mapigo ya ziada yanapatikana kati ya mapigo ya rejeleo, tunaichukulia kama kidogo 1, vinginevyo 0.

Vipi kuhusu mapigo ya kusawazisha? Wacha tuangalie mwanzo wa data:

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Toni ya majaribio inaisha na data huanza mara moja. Baadaye kidogo, baada ya kuchanganua rekodi kadhaa tofauti za sauti, tuliweza kugundua kuwa baiti ya kwanza ya data daima ni sawa (10100101b, A5h). Kompyuta inaweza kuanza kusoma data baada ya kuipokea.

Unaweza pia kuzingatia mabadiliko ya mpigo wa rejeleo wa kwanza mara tu baada ya 1 ya mwisho katika baiti ya kusawazisha. Iligunduliwa baadaye sana katika mchakato wa kutengeneza programu ya utambuzi wa data, wakati data mwanzoni mwa faili haikuweza kusomwa kwa utulivu.

Sasa hebu tujaribu kuelezea algorithm ambayo itashughulikia faili ya sauti na kupakia data.

Inapakia Data

Kwanza, hebu tuangalie mawazo machache ili kuweka algorithm rahisi:

  1. Tutazingatia faili katika umbizo la WAV pekee;
  2. Faili ya sauti lazima ianze na toni ya majaribio na isiwe na ukimya mwanzoni
  3. Faili chanzo lazima iwe na kiwango cha sampuli cha 44100 Hz. Katika kesi hii, umbali kati ya mapigo ya kumbukumbu ya sampuli 48 tayari imedhamiriwa na hatuhitaji kuihesabu kwa utaratibu;
  4. Sampuli ya muundo inaweza kuwa yoyote (8/16 bits / hatua ya kuelea) - tangu wakati wa kusoma tunaweza kuibadilisha kwa taka;
  5. Tunadhani kwamba faili ya chanzo ni ya kawaida na amplitude, ambayo inapaswa kuimarisha matokeo;

Algorithm ya kusoma itakuwa kama ifuatavyo:

  1. Tunasoma faili kwenye kumbukumbu, wakati huo huo kubadilisha muundo wa sampuli kwa bits 8;
  2. Amua nafasi ya mpigo wa kwanza katika data ya sauti. Ili kufanya hivyo, unahitaji kuhesabu idadi ya sampuli na amplitude ya juu. Kwa unyenyekevu, tutaihesabu mara moja kwa mikono. Wacha tuihifadhi kwa utofautishaji wa prev_pos;
  3. Ongeza 48 kwenye nafasi ya mpigo wa mwisho (pos := prev_pos + 48)
  4. Kwa kuwa kuongeza nafasi kwa 48 hakuhakikishii kwamba tutapata nafasi ya pigo la kumbukumbu linalofuata (kasoro za mkanda, uendeshaji usio na utulivu wa utaratibu wa gari la tepi, nk), tunahitaji kurekebisha nafasi ya pos pulse. Ili kufanya hivyo, chukua kipande kidogo cha data (pos-8; pos +8) na upate thamani ya juu ya amplitude juu yake. Nafasi inayolingana na kiwango cha juu itahifadhiwa kwenye pos. Hapa 8 = 48/6 ni mara kwa mara iliyopatikana kwa majaribio, ambayo inathibitisha kwamba tutaamua kiwango cha juu sahihi na haitaathiri msukumo mwingine ambao unaweza kuwa karibu. Katika hali mbaya sana, wakati umbali kati ya mapigo ni chini sana au zaidi ya 48, unaweza kutekeleza utafutaji wa kulazimishwa kwa pigo, lakini ndani ya upeo wa makala sitaelezea hili katika algorithm;
  5. Katika hatua ya awali, itakuwa muhimu pia kuangalia kwamba pigo la kumbukumbu lilipatikana kabisa. Hiyo ni, ikiwa unatafuta tu upeo, hii haihakikishi kuwa msukumo upo katika sehemu hii. Katika utekelezaji wangu wa hivi karibuni wa programu ya kusoma, ninaangalia tofauti kati ya viwango vya juu na vya chini vya amplitude kwenye sehemu, na ikiwa inazidi kikomo fulani, ninahesabu uwepo wa msukumo. Swali pia ni nini cha kufanya ikiwa pigo la kumbukumbu halipatikani. Kuna chaguo 2: ama data imeisha na kimya kifuate, au hii inapaswa kuchukuliwa kuwa kosa la kusoma. Hata hivyo, tutaacha hili ili kurahisisha algorithm;
  6. Katika hatua inayofuata, tunahitaji kuamua uwepo wa mapigo ya data (bit 0 au 1), kwa hili tunachukua katikati ya sehemu (prev_pos;pos) middle_pos sawa na middle_pos := (prev_pos+pos)/2 na katika baadhi ya vitongoji vya middle_pos kwenye sehemu (katikati_pos-8;middle_pos +8) hebu tuhesabu kiwango cha juu na cha chini cha amplitude. Ikiwa tofauti kati yao ni zaidi ya 10, tunaandika kidogo 1 kwenye matokeo, vinginevyo 0. 10 ni mara kwa mara kupatikana kwa majaribio;
  7. Hifadhi nafasi ya sasa katika prev_pos (prev_pos := pos)
  8. Rudia kuanzia hatua ya 3 hadi tusome faili nzima;
  9. Safu ya biti inayotokana lazima ihifadhiwe kama seti ya baiti. Kwa kuwa hatukuzingatia byte ya kusawazisha wakati wa kusoma, idadi ya bits haiwezi kuwa nyingi ya 8, na kukabiliana na bit inayohitajika pia haijulikani. Katika utekelezaji wa kwanza wa algorithm, sikujua juu ya uwepo wa byte ya kusawazisha na kwa hivyo nilihifadhi faili 8 na nambari tofauti za bits za kukabiliana. Mmoja wao alikuwa na data sahihi. Katika algorithm ya mwisho, mimi huondoa bits zote hadi A5h, ambayo huniruhusu kupata faili sahihi ya pato mara moja.

Algorithm katika Ruby, kwa wale wanaopenda
Nilichagua Ruby kama lugha ya kuandika programu, kwa sababu ... Mimi programu juu yake mara nyingi. Chaguo sio utendaji wa juu, lakini kazi ya kufanya kasi ya kusoma haraka iwezekanavyo haifai.

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

Matokeo

Baada ya kujaribu anuwai kadhaa za algorithm na viboreshaji, nilikuwa na bahati ya kupata kitu cha kufurahisha sana:

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Kwa hiyo, kwa kuzingatia masharti ya tabia, tuna mpango wa kuchora grafu. Walakini, hakuna maneno muhimu katika maandishi ya programu. Manenomsingi yote yamesimbwa kama baiti (kila thamani> 80h). Sasa tunahitaji kujua ni kompyuta gani kutoka miaka ya 80 inaweza kuokoa programu katika muundo huu.

Kwa kweli, ni sawa na mpango wa BASIC. Kompyuta ya ZX Spectrum huhifadhi programu kwa takriban muundo sawa katika kumbukumbu na huhifadhi programu kwenye mkanda. Ikiwezekana, niliangalia maneno muhimu dhidi ya meza. Walakini, matokeo yalikuwa dhahiri hasi.

Pia niliangalia maneno muhimu ya BASIC ya Atari maarufu, Commodore 64 na kompyuta nyingine kadhaa za wakati huo, ambazo niliweza kupata nyaraka, lakini bila mafanikio - ujuzi wangu wa aina za kompyuta za retro uligeuka kuwa si pana sana.

Kisha niliamua kwenda orodha, na kisha macho yangu yakaanguka kwa jina la mtengenezaji wa Radio Shack na kompyuta ya TRS-80. Haya ni majina yaliyokuwa yameandikwa kwenye vibandiko vya kaseti zilizokuwa zimelala kwenye meza yangu! Sikujua majina haya hapo awali na sikuifahamu kompyuta ya TRS-80, kwa hivyo ilionekana kwangu kuwa Radio Shack ilikuwa mtengenezaji wa kaseti za sauti kama vile BASF, Sony au TDK, na TRS-80 ulikuwa wakati wa kucheza. Kwa nini isiwe hivyo?

Kompyuta Tandy/Radio Shack TRS-80

Kuna uwezekano mkubwa kwamba rekodi ya sauti inayohusika, ambayo nilitoa kama mfano mwanzoni mwa kifungu, ilifanywa kwenye kompyuta kama hii:

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Ilibadilika kuwa kompyuta hii na aina zake (Model I / Model III / Model IV, nk) zilikuwa maarufu sana wakati mmoja (bila shaka, si katika Urusi). Ni vyema kutambua kwamba processor waliyotumia pia ilikuwa Z80. Kwa kompyuta hii unaweza kupata kwenye mtandao habari nyingi. Katika miaka ya 80, habari za kompyuta zilisambazwa ndani magazeti. Kwa sasa kuna kadhaa waigaji kompyuta kwa majukwaa tofauti.

Nilipakua emulator trs80gp na kwa mara ya kwanza niliweza kuona jinsi kompyuta hii inavyofanya kazi. Kwa kweli, kompyuta haikuauni pato la rangi; azimio la skrini lilikuwa saizi 128x48 tu, lakini kulikuwa na viendelezi vingi na marekebisho ambayo yanaweza kuongeza azimio la skrini. Pia kulikuwa na chaguzi nyingi za mifumo ya uendeshaji ya kompyuta hii na chaguzi za kutekeleza lugha ya BASIC (ambayo, tofauti na ZX Spectrum, katika baadhi ya mifano hata "haikuwaka" kwenye ROM na chaguo lolote linaweza kupakiwa kutoka kwa diski ya floppy, kama tu. OS yenyewe)

Mimi pia kupatikana matumizi kubadilisha rekodi za sauti kuwa umbizo la CAS, ambalo linaungwa mkono na waigaji, lakini kwa sababu fulani haikuwezekana kusoma rekodi kutoka kwa kaseti zangu kwa kuzitumia.

Baada ya kufikiria fomati ya faili ya CAS (ambayo iligeuka kuwa nakala kidogo-kidogo ya data kutoka kwa mkanda ambao tayari nilikuwa nao, isipokuwa kwa kichwa na uwepo wa byte ya kusawazisha), nilifanya mabadiliko machache kwenye programu yangu na niliweza kutoa faili ya CAS inayofanya kazi ambayo ilifanya kazi kwenye emulator (TRS-80 Model III):

Jinsi nilivyopata data katika umbizo lisilojulikana kutoka kwa mkanda wa sumaku

Nilitengeneza toleo la hivi punde la matumizi ya ugeuzaji na uamuzi wa kiotomatiki wa mpigo wa kwanza na umbali kati ya mipigo ya rejeleo kama kifurushi cha GEM, msimbo wa chanzo unapatikana Github.

Hitimisho

Njia ambayo tumesafiri iligeuka kuwa safari ya kuvutia katika siku za nyuma, na ninafurahi kwamba mwishowe nilipata jibu. Miongoni mwa mambo mengine, mimi:

  • Niligundua umbizo la kuhifadhi data kwenye Spectrum ya ZX na nikasoma taratibu za ROM zilizojengewa ndani za kuhifadhi/kusoma data kutoka kwa kaseti za sauti.
  • Nilifahamiana na kompyuta ya TRS-80 na aina zake, nilisoma mfumo wa uendeshaji, niliangalia programu za sampuli na hata nikapata fursa ya kufanya utatuzi katika nambari za mashine (baada ya yote, mnemonics zote za Z80 zinajulikana kwangu)
  • Aliandika matumizi kamili ya kubadilisha rekodi za sauti hadi umbizo la CAS, ambalo linaweza kusoma data ambayo haitambuliwi na shirika la "rasmi"

Chanzo: mapenzi.com

Kuongeza maoni