Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Эрьт урьдын түүх

Би чимэг техник хэрэгсэлд дуртай байсан болохоор нэг удаа Их Британи дахь худалдагчаас ZX Spectrum+ худалдаж авсан. Компьютерийн хамт би тоглоом бүхий хэд хэдэн аудио хуурцаг (зааврын хамт анхны савлагаатай), мөн тусгай тэмдэглэгээгүй хуурцаг дээр бичигдсэн програмуудыг хүлээн авсан. Гайхалтай нь, 40 жилийн настай хуурцагнаас авсан өгөгдөл нь уншихад хялбар байсан бөгөөд би бараг бүх тоглоом, програмыг тэднээс татаж авах боломжтой болсон.

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Гэсэн хэдий ч, би зарим хуурцагнаас ZX Spectrum компьютерээр хийгээгүй бичлэгүүдийг олсон. Тэд огт өөр сонсогдож байсан бөгөөд дурдсан компьютерийн бичлэгээс ялгаатай нь бүх програм, тоглоомын бичлэгт байдаг богино BASIC ачаалагчаар эхлээгүй.

Хэсэг хугацаанд энэ нь намайг зовоож байсан - би тэдний дотор юу нуугдаж байгааг олж мэдэхийг үнэхээр хүсч байсан. Хэрэв та аудио дохиог байтуудын дараалал болгон уншиж чадвал дохионы гарал үүслийг харуулсан тэмдэгт эсвэл ямар ч зүйлийг хайж олох боломжтой. Нэг төрлийн ретро-археологи.

Одоо би бүх замыг туулж, хуурцагны шошгыг хараад инээмсэглэж байна

Хариулт нь миний нүдэн дээр үргэлж байсан
Зүүн талын хуурцагны шошгон дээр TRS-80 компьютерын нэр байгаа бөгөөд үйлдвэрлэгчийн нэрний яг доор: "АНУ-ын Radio Shack үйлдвэрлэсэн" гэж бичжээ.

(Хэрэв та интригийг эцэс хүртэл хадгалахыг хүсвэл спойлерын доор бүү ороорой)

Аудио дохионы харьцуулалт

Юуны өмнө дуу бичлэгээ цахим хэлбэрт шилжүүлье. Та юу сонсогдож байгааг сонсож болно:


Ердийнх шиг ZX Spectrum компьютерийн бичлэг нь:


Аль ч тохиолдолд бичлэгийн эхэнд гэж нэрлэгддэг зүйл байдаг нисгэгчийн аялгуу - ижил давтамжтай дуу (эхний бичлэгт энэ нь маш богино <1 секунд боловч ялгагдах боломжтой). Нислэгийн аялгуу нь компьютерт өгөгдөл хүлээн авахад бэлтгэх дохио өгдөг. Дүрмээр бол компьютер бүр дохионы хэлбэр, давтамжаар зөвхөн өөрийн "өөрийн" нисгэгч аяыг таньдаг.

Дохионы хэлбэрийн талаар ямар нэг зүйлийг хэлэх шаардлагатай байна. Жишээлбэл, ZX Spectrum дээр түүний хэлбэр тэгш өнцөгт байна:

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Нислэгийн аялгууг илрүүлэх үед ZX Spectrum нь дохиог хүлээн зөвшөөрсөнийг харуулахын тулд дэлгэцийн хил дээр ээлжлэн улаан, цэнхэр өнгийн зураасыг харуулдаг. Нисгэгчийн аялгуу дуусна синхрон импульс, энэ нь компьютер өгөгдөл хүлээн авч эхлэх дохио өгдөг. Энэ нь богино хугацаанд тодорхойлогддог (туршилтын ая болон дараагийн өгөгдөлтэй харьцуулахад) (зураг харна уу)

Синхрончлолын импульсийг хүлээн авсны дараа компьютер дохионы өсөлт/уналт бүрийг бүртгэж, үргэлжлэх хугацааг хэмждэг. Хэрэв үргэлжлэх хугацаа нь тодорхой хязгаараас бага бол санах ойд 1-р бит бичигдэнэ, үгүй ​​бол 0. Битүүдийг байт болгон цуглуулж, N байт хүлээн авах хүртэл процесс давтагдана. N тоог ихэвчлэн татаж авсан файлын толгой хэсгээс авдаг. Ачаалах дараалал дараах байдалтай байна.

  1. нисгэгчийн аялгуу
  2. толгой (тогтмол урт), татаж авсан өгөгдлийн хэмжээ (N), файлын нэр, төрлийг агуулдаг
  3. нисгэгчийн аялгуу
  4. өгөгдөл өөрөө

Өгөгдөл зөв ачаалагдсан эсэхийг шалгахын тулд ZX Spectrum гэж нэрлэгддэг зүйлийг уншдаг парит байт (паритын байт) нь файлыг хадгалах үед бүх бичмэл өгөгдлийн байтыг XOR хийх замаар тооцдог. Файлыг уншиж байх үед компьютер нь хүлээн авсан өгөгдлөөс паритет байтыг тооцоолж, үр дүн нь хадгалагдсанаас ялгаатай бол "R Tape ачаалах алдаа" гэсэн алдааны мэдэгдлийг харуулна. Хатуухан хэлэхэд, компьютер уншиж байх үед импульсийг таньж чадахгүй бол (алдсан эсвэл үргэлжлэх хугацаа нь тодорхой хязгаарт тохирохгүй) энэ мессежийг эрт гаргаж болно.

Тэгэхээр одоо үл мэдэгдэх дохио ямар байхыг харцгаая.

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Энэ бол туршилтын өнгө юм. Дохионы хэлбэр нь мэдэгдэхүйц ялгаатай боловч дохио нь тодорхой давтамжийн богино импульсийн давтагдахаас бүрддэг нь тодорхой юм. 44100 Гц-ийн түүврийн давтамжтай үед "оргил"-ын хоорондох зай нь ойролцоогоор 48 дээж байна (энэ нь ~918 Гц давтамжтай тохирч байна) Энэ зургийг санацгаая.

Одоо өгөгдлийн фрагментийг харцгаая:

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Хэрэв бид бие даасан импульсийн хоорондох зайг хэмжвэл "урт" импульсийн хоорондох зай ~48, богино импульсийн хоорондох зай ~24 хэвээр байна. Цаашид бага зэрэг харвал эцэст нь 918 Гц давтамжтай "лавлагаа" импульс нь файлын эхнээс төгсгөл хүртэл тасралтгүй дагалддаг болохыг би хэлэх болно. Өгөгдөл дамжуулах үед лавлагаа импульсийн хооронд нэмэлт импульс тохиолдвол бид үүнийг бит 1, эс тэгвээс 0 гэж үзнэ гэж үзэж болно.

Синк импульсийн талаар юу хэлэх вэ? Өгөгдлийн эхлэлийг харцгаая:

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Туршилтын аялгуу дуусч, өгөгдөл нэн даруй эхэлнэ. Хэсэг хугацааны дараа хэд хэдэн өөр аудио бичлэгийг шинжилсний дараа бид эхний байт өгөгдөл үргэлж ижил байдгийг олж мэдсэн (10100101b, A5h). Компьютер өгөгдлийг хүлээн авсны дараа уншиж эхлэх боломжтой.

Та мөн синхрончлолын байт дахь сүүлчийн 1-ийн дараа эхний лавлагааны импульсийн шилжилтийг анхаарч үзэх боломжтой. Энэ нь файлын эхэнд байгаа өгөгдлийг тогтвортой уншиж чадахгүй байх үед өгөгдлийг таних программыг боловсруулах явцад нэлээд хожуу нээсэн юм.

Одоо аудио файлыг боловсруулж, өгөгдлийг ачаалах алгоритмыг тайлбарлахыг хичээцгээе.

Өгөгдлийг ачаалж байна

Эхлээд алгоритмыг энгийн байлгахын тулд хэд хэдэн таамаглалыг авч үзье.

  1. Бид зөвхөн WAV форматтай файлуудыг авч үзэх болно;
  2. Аудио файл нь туршилтын аялгуугаар эхлэх ёстой бөгөөд эхэнд чимээгүй байх ёсгүй
  3. Эх файл нь 44100 Гц түүвэрлэлтийн давтамжтай байх ёстой. Энэ тохиолдолд 48 дээжийн лавлагааны импульсийн хоорондох зай аль хэдийн тодорхойлогдсон бөгөөд бид үүнийг програмын дагуу тооцоолох шаардлагагүй болно;
  4. Түүврийн формат нь дурын байж болно (8/16 бит/хөвөгч цэг) - уншиж байх үед бид үүнийг хүссэн формат руу хөрвүүлэх боломжтой;
  5. Бид эх файлыг далайцаар хэвийн болгосон гэж үздэг бөгөөд энэ нь үр дүнг тогтворжуулах ёстой;

Унших алгоритм нь дараах байдалтай байна.

  1. Бид файлыг санах ой руу уншиж, нэгэн зэрэг жишээ форматыг 8 бит болгон хөрвүүлдэг;
  2. Аудио өгөгдөл дэх эхний импульсийн байрлалыг тодорхойлно. Үүнийг хийхийн тулд та хамгийн их далайцтай дээжийн тоог тооцоолох хэрэгтэй. Энгийн байхын тулд бид үүнийг гараар нэг удаа тооцоолох болно. Үүнийг prev_pos хувьсагч руу хадгалъя;
  3. Сүүлийн импульсийн байрлалд 48 нэмнэ (pos := prev_pos + 48)
  4. Байрлалыг 48-аар нэмэгдүүлэх нь бид дараагийн лавлагааны импульсийн байрлалд (соронзон хальсны согог, соронзон хальсны хөтөч механизмын тогтворгүй ажиллагаа гэх мэт) хүрэх баталгаа болохгүй тул бид импульсийн байрлалыг тохируулах хэрэгтэй. Үүнийг хийхийн тулд жижиг өгөгдлийн хэсгийг (pos-8;pos+8) аваад түүн дээрх хамгийн их далайцын утгыг ол. Хамгийн ихдээ тохирох байрлал нь pos-д хадгалагдана. Энд 8 = 48/6 нь туршилтаар олж авсан тогтмол бөгөөд энэ нь бид зөв максимумыг тодорхойлж, ойролцоо байж болох бусад импульсүүдэд нөлөөлөхгүй гэдгийг баталгаажуулдаг. Маш муу тохиолдолд, импульсийн хоорондох зай 48-аас хамаагүй бага эсвэл түүнээс их байвал та импульсийн албадан хайлт хийж болно, гэхдээ нийтлэлийн хүрээнд би үүнийг алгоритмд тайлбарлахгүй;
  5. Өмнөх алхам дээр лавлагааны импульс огт олдсон эсэхийг шалгах шаардлагатай болно. Өөрөөр хэлбэл, хэрэв та хамгийн дээд хэмжээг хайж байгаа бол энэ нь энэ сегментэд импульс байгаа гэсэн баталгаа биш юм. Унших програмыг хамгийн сүүлд хэрэгжүүлэхдээ би сегмент дээрх хамгийн их ба хамгийн бага далайцын утгын зөрүүг шалгаж, хэрэв энэ нь тодорхой хязгаараас давсан бол импульс байгаа эсэхийг тооцдог. Хэрэв лавлагааны импульс олдохгүй бол юу хийх вэ гэсэн асуулт гарч ирнэ. Хоёр сонголт байна: өгөгдөл дуусч, чимээгүй болно, эсвэл үүнийг унших алдаа гэж үзэх хэрэгтэй. Гэсэн хэдий ч, бид алгоритмыг хялбарчлахын тулд үүнийг орхих болно;
  6. Дараагийн алхамд бид өгөгдлийн импульс (бит 0 эсвэл 1) байгаа эсэхийг тодорхойлох шаардлагатай бөгөөд үүний тулд бид сегментийн дунд хэсгийг (prev_pos;pos) дунд_посыг дунд_пос := (өмнөх_пос+pos)/2-той тэнцүү хэмжээгээр авна. сегментийн дундын_посын зарим хэсэгт (middle_pos-8;middle_pos +8) хамгийн их ба хамгийн бага далайцыг тооцоолъё. Хэрэв тэдгээрийн хоорондын зөрүү 10-аас их байвал бид үр дүнд 1-р бит бичнэ, үгүй ​​бол 0. 10 нь туршилтаар олж авсан тогтмол;
  7. Одоогийн байрлалыг өмнөх_post-д хадгалах (өмнөх_пос := pos)
  8. Бид файлыг бүхэлд нь унших хүртэл 3-р алхамаас эхлэн давтана;
  9. Үүссэн бит массив нь байтуудын багц хэлбэрээр хадгалагдах ёстой. Уншихдаа бид синхрончлолын байтыг харгалзаагүй тул битийн тоо 8-ын үржвэр биш байж болох бөгөөд шаардлагатай битийн офсет мөн тодорхойгүй байна. Алгоритмыг анх хэрэгжүүлэхэд би синхрончлолын байт байдгийг мэдэхгүй байсан тул өөр өөр тооны офсет бит бүхий 8 файлыг хадгалсан. Тэдний нэг нь зөв мэдээлэл агуулсан. Эцсийн алгоритмд би зүгээр л A5h хүртэлх бүх битийг устгадаг бөгөөд энэ нь надад зөв гаралтын файлыг шууд авах боломжийг олгодог.

Сонирхсон хүмүүст зориулсан Ruby хэл дээрх алгоритм
Програм бичих хэлээр би Ruby-г сонгосон, учир нь... Би ихэнхдээ үүн дээр программ хийдэг. Сонголт нь өндөр гүйцэтгэлтэй биш боловч унших хурдыг аль болох хурдан болгох даалгавар нь үнэ цэнэтэй зүйл биш юм.

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

үр дүн

Алгоритм ба тогтмолуудын хэд хэдэн хувилбарыг туршиж үзээд би маш сонирхолтой зүйлийг олж авсан нь азтай байсан:

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Тиймээс, тэмдэгтийн мөрүүдээс харахад бид график зурах програмтай болсон. Гэсэн хэдий ч програмын текстэнд түлхүүр үг байхгүй байна. Бүх түлхүүр үгс нь байт хэлбэрээр кодлогдсон (утга бүр > 80 цаг). Одоо бид 80-аад оны аль компьютер энэ форматтай програмыг хадгалж болохыг олж мэдэх хэрэгтэй.

Үнэн хэрэгтээ энэ нь BASIC програмтай маш төстэй юм. ZX Spectrum компьютер нь санах ойд програмуудыг ойролцоогоор ижил форматаар хадгалж, програмуудыг соронзон хальсанд хадгалдаг. Ямар ч тохиолдолд би түлхүүр үгсийн эсрэг шалгаж үзсэн ширээ. Гэсэн хэдий ч үр дүн нь мэдээж сөрөг байсан.

Би мөн тухайн үеийн алдартай Atari, Commodore 64 болон бусад хэд хэдэн компьютеруудын BASIC түлхүүр үгсийг шалгаж үзсэн бөгөөд үүний тулд баримт бичгийг олж чадсан боловч амжилтанд хүрээгүй - чимэг компьютерийн төрлүүдийн талаархи миний мэдлэг тийм ч өргөн биш байсан.

Тэгээд би явахаар шийдсэн Жагсаалт, тэгээд миний харц үйлдвэрлэгч Radio Shack болон TRS-80 компьютерийн нэр дээр тусав. Энэ бол миний ширээн дээр хэвтэж байсан хуурцагны шошгон дээр бичсэн нэрс юм! Би эдгээр нэрийг өмнө нь мэддэггүй байсан бөгөөд TRS-80 компьютерийг сайн мэддэггүй байсан тул Radio Shack нь BASF, Sony эсвэл TDK гэх мэт аудио кассет үйлдвэрлэгч байсан бөгөөд TRS-80 нь тоглуулах хугацаа юм шиг санагдаж байсан. Яагаад үгүй ​​гэж?

Компьютерийн Tandy/Radio Shack TRS-80

Өгүүллийн эхэнд миний жишээ болгон дурдсан аудио бичлэгийг ийм компьютер дээр хийсэн байх магадлал өндөр байна.

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Энэ компьютер болон түүний сортууд (Загвар I/III/Загвар IV гэх мэт) нэгэн цагт маш их алдартай байсан (мэдээж Орост биш). Тэдний ашигласан процессор нь мөн Z80 байсан нь анхаарал татаж байна. Энэ компьютерийн хувьд та интернетээс олж болно маш их мэдээлэл. 80-аад онд компьютерийн мэдээллийг түгээж эхэлсэн сэтгүүлүүд. Одоогийн байдлаар хэд хэдэн байна эмуляторууд өөр өөр платформд зориулсан компьютерууд.

Би эмулятор татаж авсан trs80gp мөн анх удаа би энэ компьютер хэрхэн ажилладагийг харж чадсан. Мэдээжийн хэрэг, компьютер өнгөт гаралтыг дэмждэггүй, дэлгэцийн нягтрал нь ердөө 128x48 пиксел байсан ч дэлгэцийн нягтралыг нэмэгдүүлэх боломжтой олон өргөтгөл, өөрчлөлтүүд байсан. Мөн энэ компьютерт зориулсан үйлдлийн системийн олон сонголтууд болон BASIC хэлийг хэрэгжүүлэх сонголтууд байсан (энэ нь ZX Spectrum-аас ялгаатай нь зарим загварт ROM-д "анивчихгүй" байсан бөгөөд ямар ч сонголтыг уян дискнээс ачаалж болно. үйлдлийн систем өөрөө)

Би ч бас олсон ашиглалтын аудио бичлэгийг эмуляторууд дэмждэг CAS формат руу хөрвүүлэхийн тулд зарим шалтгааны улмаас тэдгээрийг ашиглан миний кассетаас бичлэг унших боломжгүй байсан.

CAS файлын форматыг олж мэдээд (энэ нь синхрончлолын байт бүхий толгой хэсгийг эс тооцвол миний гарт байсан соронзон хальсны өгөгдлийн бага багаар хуулбарласан) би үүнийг хийсэн. Миний программд цөөн хэдэн өөрчлөлт орсон бөгөөд эмулятор дээр ажиллаж байсан CAS файлыг гаргаж чадсан (TRS-80 Model III):

Би соронзон хальснаас үл мэдэгдэх форматтай өгөгдлийг хэрхэн сэргээсэн

Би эхний импульс болон лавлагаа импульсийн хоорондох зайг автоматаар тодорхойлох хөрвүүлэх хэрэгслийн хамгийн сүүлийн хувилбарыг GEM багц хэлбэрээр бүтээсэн бөгөөд эх кодыг эндээс авах боломжтой. Github.

дүгнэлт

Бидний туулсан зам өнгөрсөн үе рүү чиглэсэн сонирхолтой аялал болж, эцэст нь хариултаа олсондоо баяртай байна. Бусад зүйлсийн дотор би:

  • Би ZX Spectrum-д өгөгдөл хадгалах форматыг олж мэдсэн бөгөөд аудио кассетаас өгөгдлийг хадгалах/уншихад зориулагдсан ROM горимуудыг судалсан.
  • Би TRS-80 компьютер болон түүний сортуудтай танилцаж, үйлдлийн системийг судалж, жишээ програмуудыг үзэж, тэр ч байтугай машины кодуудад дибаг хийх боломжтой болсон (эцэст нь Z80 бүх мнемоникууд надад танил юм)
  • Аудио бичлэгийг CAS формат руу хөрвүүлэх бүрэн хэмжээний хэрэгслийг бичсэн бөгөөд энэ нь "албан ёсны" хэрэгсэлд танигдаагүй өгөгдлийг унших боломжтой.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх