Практика раскодировки на Python

Здесь рассмотрены практические приемы и особенности работы с оцифрованными программными файлами Д3-28.

Кассетный накопитель Д3-28

Программы Д3-28 записываются встроенным накопителем на магнитную ленту стандартных магнитофонных кассет
МК-60/МК-90 или аналогичных зарубежного производства.

Схемотехнику канала записи/чтения можно изучить по принципиальной схеме ПЕЛ3.057.004 Э3. Блок управления ОЗУ и НМЛ. Лист 2   Фрагмент этой схемы приводим ниже:

Обвязка магнитной головки НМЛ

Зелеными овалами отмечены контакты разъема, соединяющего магнитную головку с блоком управления.
Левая красная стрелка указывает элементы схемы, которые участвуют в записи информации на ленту, правая красная стрелка указывает движение информации при считывании.
Для нас важно, что при записи импульсы на магнитную головку подаются напрямую с TTL-выходов микросхем без разделительных конденсаторов. Это обеспечивает максимальную крутизну фронтов записи и, соответственно, наилучшие условия для чтения информации с магнитной ленты.

Отсюда следует важный практический вывод: при оцифровке программ Д3-28 современными средствами необходимо так же использовать усилитель чтения с минимальным (лучше нулевым) использованием конденсаторов в цепи сигнала. Для оцифровки имеющихся у автора кассет использовался самодельный усилитель на операционном усилителе К157УД2А.

Усилитель для оцифровки кассет Д3-28

Оцифрованный в WAV-файл с помощью данного усилителя Бэйсик имеет такую форму сигнала:

Фрагмент диаграммы оцифрованного сигнала

Такая форма сигнала может считаться идеальной для раскодировки. Сигналы, которые отличаются от «идеала» и что с ними делать мы рассмотрим в отдельном материале.
На приведенном фрагменте (все картинки с аудиофайлами получены с помощью программы Audacity) верхние импульсы соответствуют каналу нулей, нижние единиц. Причем значение имеет не форма импульса, не амплитуда, не полярность, а только порядок следования импульсов друг за другом. Подробно все описано в материале Sinus’a. Добавим, что такой принцип записи очень снижает требования к скорости протяжки ленты при оцифровке и облегчает нашу работу.
Собственно, Python-программа всего лишь просматривает последовательно все сэмплы файла, определяет к какому каналу (нулей или единиц) принадлежит очередной пик и записывает в выходную последовательность очередной бит информации.

Для практической работы используем «неидеальную» оцифровку, чтобы увидеть возможности по поиску ошибок в процессе раскодирования. Файл WAV возьмем покороче, чтобы процедура раскодировки программой была быстрой. Имя этого тренировочного файла zagr.wav, это загрузчик от чего-то.
Запускаем его раскодировку, как написано здесь и получаем два файла: zagr.txt и zagr.decode. Текстовый файл нам пока не нужен, сначала посмотрим в decode. Вот что там:

Выходной текстовый файл с отладочной информацией. Колонки в файле означают следующее:
1-я. Номер байта
2-я. Битовое представление байта
3-я. Бит четности из звукового файла
4-я. Бит четности, вычисленный по раскодировке байта
5-я. Знак Плюс если биты совпали, знак Вопрос если биты не совпали (ошибка раскодировки байта)
6-я. Десятичное представление байта (как в документации Д3-28)
7-я. Номер сэмпла, которым начинается соответствующий раскодированный байт (для поиска ошибок)
8-я. Тот же номер сэмпла, только деленный пополам, для удобства работы в Audacity. В Audacity именно это число используем для установки курсора на сэмпл требуемого байта

0 01001100 1 1 + 0412 0 0
1 11001011 1 1 + 1211 849 424
2 11010100 0 0 + 1304 1527 763
3 00001110 1 1 + 0014 2142 1071
4 01001100 1 1 + 0412 2841 1420
5 11100010 0 0 + 1402 3493 1746
6 01001100 1 1 + 0412 4112 2056
7 11000011 0 0 + 1203 4775 2387
8 01001101 0 0 + 0413 5394 2697
9 10101000 1 1 + 1008 6016 3008
10 01001101 0 0 + 0413 6661 3330
11 01011000 1 1 + 0508 7290 3645
12 11010010 0 0 + 1302 7933 3966
13 00010101 1 1 + 0105 8536 4268
14 11010011 1 1 + 1303 9239 4619
15 01011100 0 0 + 0512 9885 4942
16 01001100 1 1 + 0412 10494 5247
17 10101001 0 0 + 1009 11179 5589
18 11010001 0 0 + 1301 11830 5915
19 11111111 0 0 + 1515 12462 6231
20 10110000 1 1 + 1100 13094 6547
21 10011000 1 1 + 0908 13725 6862
22 11100100 0 0 + 1404 14351 7175
23 10011000 1 1 + 0908 14930 7465
24 11010110 1 1 + 1306 15603 7801
25 00001111 0 0 + 0015 16239 8119
26 10101110 0 1 ? 1014 16890 8445
27 10001000 1 0 ? 0808 17578 8789
28 01101110 0 1 ? 0614 18251 9125
29 00110101 1 0 ? 0305 18880 9440
30 10001000 0 0 + 0808 19665 9832
31 01011101 1 1 + 0513 20274 10137
32 10111000 0 0 + 1108 20953 10476
33 00000110 1 0 ? 0006 21570 10785
34 01101000 1 1 + 0608 22257 11128
35 01101000 1 1 + 0608 22923 11461
36 01101000 1 1 + 0608 23577 11788
37 00110100 0 1 ? 0304 24235 12117
38 00100100 1 0 ? 0204 24848 12424
Контрольная сумма = 610
Раскодирование начато в 03.06.2019-15.33.15 , окончено в 03.06.2019-15.33.21

Как видим в раскодировке есть знаки вопроса, значит она прошла с ошибками. Попытаемся выяснить, в чем проблема. Для этого открываем в Audacity звуковой файл zagr.wav и устанавливаем курсор на сэмпл, номер которого указан в последней колонке строки, где стоит первый по порядку вопросик (может в этом месте поправим и все остальное исправится?). Итак смотрим на сэмпл 8445.

Фрагмент диаграммы с ошибкой

Курсором на диаграмме отмечена «Позиция аудио» равная 8445. Осмотрим внимательно соседние пики. Легко можно заметить, что относительно позиции 8445 левый пик и правый отстоят на существенно разное количество сэмплов. Это проиллюстрировано на следующих диаграммах:Как видим выше, левый ближайший пик отстоит всего на 15 сэмплов.А ближайший правый пик — на 58 сэмплов. Очень похоже, что именно в этом источник данной ошибки — то есть программа не смогла распознать близкорасположенные пики. Помочь этому делу достаточно несложно — нужно лишь сдвинуть канал единиц (нижний график) так, чтобы между пиками было примерно равное расстояние. Несложная арифметика подсказывает, что если средствами Audacity удалить 21 сэмпл в нижнем канале (это надо делать в самом начале файла, там, где еще нет записанных сигналов), то расстояние влево будет 58-21=37 сэмплов, расстояние вправо 15+21=36 сэмплов. Точнее и не надо.
Итак, проделываем эту операцию и сохраняем результат в новый файл, например zagr1.wav. Раскодируем, смотрим файл zagr1.decode (здесь удален текст начальной подсказки):
0 01001100 1 1 + 0412 0 0
1 11001011 1 1 + 1211 753 376
2 11010100 0 0 + 1304 1431 715
3 00001110 1 1 + 0014 2094 1047
4 01001100 1 1 + 0412 2745 1372
5 11100010 0 0 + 1402 3397 1698
6 01001100 1 1 + 0412 4064 2032
7 11000011 0 0 + 1203 4679 2339
8 01001101 0 0 + 0413 5304 2652
9 10101000 1 1 + 1008 5920 2960
10 01001101 0 0 + 0413 6565 3282
11 01011000 1 1 + 0508 7196 3598
12 11010010 0 0 + 1302 7837 3918
13 00010101 1 1 + 0105 8488 4244
14 11010011 1 1 + 1303 9143 4571
15 01011100 0 0 + 0512 9789 4894
16 01001100 1 1 + 0412 10446 5223
17 10101001 0 0 + 1009 11083 5541
18 11010001 0 0 + 1301 11740 5870
19 11111111 0 0 + 1515 12370 6185
20 10110000 1 1 + 1100 13006 6503
21 10011000 1 1 + 0908 13629 6814
22 11100100 0 0 + 1404 14255 7127
23 10011000 1 1 + 0908 14882 7441
24 11010110 1 1 + 1306 15507 7753
25 00001111 0 0 + 0015 16143 8071
26 11010111 0 0 + 1307 16800 8400
27 01000100 0 0 + 0404 17448 8724
28 10110111 0 0 + 1107 18094 9047
29 00011011 0 0 + 0111 18748 9374
30 11100010 0 0 + 1402 19402 9701
31 00010111 0 0 + 0107 20080 10040
32 11101110 0 0 + 1414 20696 10348
33 00000001 1 1 + 0001 21372 10686
34 01011010 0 0 + 0510 22017 11008
35 01011010 0 0 + 0510 22694 11347
36 01011010 0 0 + 0510 23348 11674
37 01001101 0 0 + 0413 24006 12003
38 00001001 0 0 + 0009 24632 12316
39 01011100 0 0 + 0512 25300 12650
Контрольная сумма = 610
Раскодирование начато в 02.06.2019-20.54.54 , окончено в 02.06.2019-20.54.59

Видим, что вопросиков в раскодировке нет. Значит проверка бита нечетности ошибок не выявила и файл, почти наверняка, раскодировался правильно. Почему «почти» — потому, что не все ошибки распознаются с помощью бита четности — об этом хорошо написано у Sinus’a.
И еще один признак говорит, что все как надо: на странице Архив программ для Д3-28, кассета 29В, видим, что контрольную сумму 610 имеет загрузчик ВТ-9Р.
Дополнение: для оценки времени раскодировки программ приводим время для «родного» Бэйсика 157107 в оцифровке:
с частотой 8 кГц — 1 минута 46 секунд,
с частотой 44 кГц — 8 минут 56 секунд
(процессор Intel BYT-M 2Core 2840GHz)

Виталий