Магниттік таспадан белгісіз пішімдегі деректерді қалай қалпына келтірдім

тарихын

Мен ретро жабдықтарды жақсы көретін болғандықтан, мен бір рет Ұлыбританиядағы сатушыдан 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 loading error» қате туралы хабарды көрсетеді. Нақты айтқанда, компьютер оқу кезінде импульсті тани алмаса (өткізіп алмаса немесе оның ұзақтығы белгілі бір шектеулерге сәйкес келмесе) бұл хабарламаны ертерек бере алады.

Енді белгісіз сигналдың қандай болатынын көрейік:

Магниттік таспадан белгісіз пішімдегі деректерді қалай қалпына келтірдім

Бұл пилоттық үн. Сигналдың пішіні айтарлықтай ерекшеленеді, бірақ сигнал белгілі бір жиіліктегі қысқа импульстарды қайталаудан тұратыны анық. 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 импульсінің орнын реттеу керек. Ол үшін деректердің шағын бөлігін (pos-8;pos+8) алып, ондағы максималды амплитудалық мәнді табыңыз. Максимумға сәйкес позиция позда сақталады. Мұнда 8 = 48/6 эксперименталды түрде алынған тұрақты шама, ол біз дұрыс максимумды анықтайтынымызға және жақын жерде болуы мүмкін басқа импульстарға әсер етпейтінімізге кепілдік береді. Өте нашар жағдайларда, импульстар арасындағы қашықтық 48-ден әлдеқайда аз немесе одан жоғары болғанда, сіз импульсті мәжбүрлі іздеуді жүзеге асыра аласыз, бірақ мақаланың аясында мен мұны алгоритмде сипаттамаймын;
  5. Алдыңғы қадамда анықтамалық импульстің мүлде табылғанын тексеру қажет болады. Яғни, егер сіз жай ғана максималды іздесеңіз, бұл импульстің осы сегментте бар екеніне кепілдік бермейді. Оқу бағдарламасын соңғы орындауымда сегменттегі максималды және минималды амплитудалық мәндер арасындағы айырмашылықты тексеремін, ал егер ол белгілі бір шектен асып кетсе, импульстің болуын есептеймін. Мәселе сонымен қатар анықтамалық импульс табылмаса не істеу керек. 2 нұсқа бар: не деректер аяқталды, содан кейін үнсіздік орнайды немесе бұл оқу қатесі деп қарастырылуы керек. Дегенмен, алгоритмді жеңілдету үшін біз мұны өткізбейміз;
  6. Келесі қадамда деректер импульсінің (бит 0 немесе 1) болуын анықтау керек, ол үшін сегменттің ортасын (prev_pos;pos) middle_pos := (prev_pos+pos)/2 мәніне тең аламыз және сегменттегі middle_pos кейбір төңірегінде (middle_pos-8;middle_pos +8) максималды және минималды амплитуданы есептейік. Егер олардың арасындағы айырмашылық 10-нан көп болса, нәтижеге 1 бит жазамыз, әйтпесе 0. 10 – тәжірибе арқылы алынған тұрақты шама;
  7. Ағымдағы орынды алдыңғы_позицияда сақтаңыз (алдыңғы_позиция:= 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/Model III/Model IV, т.б.) бір кездері өте танымал болған (әрине, Ресейде емес). Бір қызығы, олар пайдаланған процессор да Z80 болды. Бұл компьютер үшін сіз Интернетте таба аласыз көп ақпарат. 80-жылдары компьютерлік ақпараттар таратылды журналдар. Қазіргі уақытта бірнеше бар эмуляторлар әртүрлі платформаларға арналған компьютерлер.

Мен эмуляторды жүктеп алдым trs80gp мен бұл компьютердің қалай жұмыс істейтінін алғаш рет көрдім. Әрине, компьютер түсті шығаруды қолдамады, экранның ажыратымдылығы тек 128x48 пиксель болды, бірақ экранның ажыратымдылығын арттыратын көптеген кеңейтімдер мен модификациялар болды. Сондай-ақ, осы компьютерге арналған операциялық жүйелердің көптеген нұсқалары және BASIC тілін енгізу опциялары болды (ол ZX Spectrum-дан айырмашылығы, кейбір үлгілерде тіпті ROM-ға «жарқылдамайды» және кез келген опцияны дискеттік дискіден жүктеуге болады, мысалы ОЖ өзі)

Мен де таптым утилита аудиожазбаларды эмуляторлар қолдайтын CAS пішіміне түрлендіру үшін, бірақ қандай да бір себептермен олардың көмегімен менің кассеталардағы жазбаларды оқу мүмкін болмады.

CAS файл пішімін анықтағаннан кейін (ол қолымда болған таспадағы деректердің бірте-бірте көшірмесі болып шықты, синхрондау байты бар тақырыпты қоспағанда) мен Менің бағдарламама бірнеше өзгерістер енгізілді және эмуляторда жұмыс істейтін жұмыс істейтін CAS файлын шығара алды (TRS-80 III моделі):

Магниттік таспадан белгісіз пішімдегі деректерді қалай қалпына келтірдім

Мен GEM пакеті ретінде бірінші импульсті және анықтамалық импульстар арасындағы қашықтықты автоматты түрде анықтайтын түрлендіру утилитасының соңғы нұсқасын жасадым, бастапқы код мына жерде қол жетімді: GitHub.

қорытынды

Біз жүріп өткен жол өткенге қызықты саяхат болды және мен соңында жауап тапқаныма қуаныштымын. Басқа нәрселермен қатар мен:

  • Мен ZX Spectrum жүйесінде деректерді сақтау пішімін анықтадым және аудио кассеталардан деректерді сақтау/оқу үшін кірістірілген ROM режимдерін зерттедім.
  • Мен TRS-80 компьютерімен және оның сорттарымен таныстым, операциялық жүйені зерттедім, үлгілік бағдарламаларды қарап шықтым, тіпті машина кодтарында отладка жасау мүмкіндігіне ие болдым (ақыр соңында, Z80 мнемотехникасының бәрі маған таныс)
  • Аудио жазбаларды CAS пішіміне түрлендіруге арналған толыққанды қызметтік бағдарлама жазды, ол «ресми» қызметтік бағдарлама танымайтын деректерді оқи алады.

Ақпарат көзі: www.habr.com

пікір қалдыру