Раскодировщик работает под управлением Python не ниже 3 версии. Использует дополнительные библиотеки wave, numpy, os, datetime.
Запуск в консоли Линукс командой «python3 ./d3-28_wav_decoder.py»
import wave
import numpy as np
import os
import datetime
atime = datetime.datetime.today().strftime("%d.%m.%Y-%H.%M.%S") # Время начала раскодировки
types = {
1: np.int8,
2: np.int16,
4: np.int32
}
duration = 0.05 # second # Параметры звукового сигнала
freq = 400 # Hz
(helptext)
print()
print('Список звуковых файлов текущего каталога: ')
wav_files = [f for f in os.listdir() if f.endswith('.wav')]
print('\n'.join(wav_files))
inputfile = input("Введите имя WAV файла для раскодировки: ")
if not os.path.exists(inputfile):
print ('Файл с таким именем в текущем каталоге не найден. Начните с начала.')
print()
os.system('play --no-show-progress --null --channels 1 synth %s sine %f' % (duration, freq)) # Звуковой сигнал
quit()
print()
print(atime, "Начат процесс раскодирования....")
os.system('play --no-show-progress --null --channels 1 synth %s sine %f' % (0.05, 1600)) # Звуковой сигнал
outfile = inputfile.split('.')
out_file = open(str(outfile[0])+'.decode', 'w') # Выходной текстовый файл с отладочной информацией.
out_file1 = open(str(outfile[0])+'.txt', 'w') # Выходной текстовый фал. Содержит только байты команд Д3-28. Полностью пригоден для исполнения в имитаторе
wav = wave.open(inputfile, mode="r") # Чтение входного WAV-файла
(nchannels, sampwidth, framerate, nframes, comptype, compname) = wav.getparams() # Чтение параметров входного WAV-файла
content = wav.readframes(nframes)
samples = np.fromstring(content, dtype=types[sampwidth]) # Из звукового файла вытаскиваются только значения отдельных сэмплов
samples = abs(samples) # Все полуволны звукового файла становятся положительными, чтобы проще было искать максимумы
len1 = len(samples) ### Количество сэмплов всего (в обоих каналах)
print("Отсекаем помеху:")
print(" ",str(len1), end="\r") # Вывод хода обработки
pomeha = max(samples)/3 # Устанвливается уровень "помехи". Меньше этого уровня все приравнивается нулю
for i in range(0,len1) : # Отсекается сигнал ниже уровня помехи.
if abs(samples[i]) < pomeha :
samples[i] = 0.0
if (i % 1000) == 0:
print(str(i), end="\r") # Вывод хода обработки
print("Прореживаем локальные максимумы:")
print(" ",str(len1), end="\r") # Вывод хода обработки
for i in range(1,len1) : #
if (abs(samples[i]) > 0) & (abs(samples[i-1]) > 0) :
samples[i] = 0.0
samples[i-1] = 0.0
if (i % 1000) == 0:
print(str(i), end="\r") # Вывод хода обработки
# Далее обрабатываем WAV-файл и находим значения номеров сэмплов для каждого из максимумов амплитуды
# Обработка сэмплов происходит последовательно сразу обоих каналов без разделения по каналам
bit_code_raw = "" # Это строка, в которую записываются нули и единицы последовательно, если найден локальный максимум
nsample = 0
nsample1 = 0
nbyte = 0
max_temp = 0 # Это текущий номер сэмпла с локальными максимумом амплитуды
byte_sample = [0] # Номера сэмплов каждого девятого бита в раскодированном байте (для поиска ошибок)
while nsample < (len1-4) :
nbyte = nbyte + 1
if samples[nsample] == 0: # Пропускаем пустое место между локальными максимумами
nsample = nsample+1
else :
nsample1 = nsample
max_temp = nsample1
while samples[nsample1] > 0: # Находим локальный максимум, запоминаем в max_temp
if samples[nsample1+2] > samples[nsample1]:
max_temp = nsample1+2
nsample1 = nsample1+2
if (max_temp % 2) == 0: # Если номер сэмпла четный (канал нулей в WAVчике)
bit_code_raw = bit_code_raw + "0" # то запишем в строку нолик
else: # Если номер сэмпла нечетный (канал единиц в WAVчике)
bit_code_raw = bit_code_raw + "1" # то запишем в строку единичку
if ((len(bit_code_raw) % 9) == 0) : # Запоминаем номер сэмпла каждого девятого бита в раскодированном байте
byte_sample.append(nsample)
nsample = nsample1
polubyte = {"0000":"00", "0001":"01", "0010":"02", "0011":"03", "0100":"04", "0101":"05", "0110":"06", "0111":"07", "1000":"08", "1001":"09", "1010":"10", "1011":"11", "1100":"12", "1101":"13", "1110":"14", "1111":"15"} # Справочник перекодировки из битовых тетрад в десятичные
bit_code = [str(i) for i in bit_code_raw] # Преобразуем строку битов в список строковых значений
code = "".join(bit_code) # Убираем разделители между строковыми значениями
#len3 = (len(bit_code_raw))/9
#print(len3)
len3a = len(code)/9 # Количество байт в раскодировке
print(len3a)
if (len3a - int(len3a)) > 0 : # Если количество 9-битовых байт дробное (при ошибках)
while (len(code) - int(len(code))) > 0 : # При дробном количестве дополняем нулями до целого
code = code + "0"
len3a = len(code)/9
chet = [0,2,4,6,8] # Справочник четных символов в байте
nechet = [1,3,5,7] # Справочник нечетных символов в байте
bit_chetnosti = ""
ks = 0
print('\n'.join(helptext), file=out_file)
for i in range(0, int(len3a), 1) :
i9 = i*9 # Номер первого символа байта (первого полубайта)
i94 = i*9 + 4 # Номер первого символа второго полубайта
i98 = i*9+8 # Номер символа четности
byte = code[i9 : i98] # Значение раскодированного текущего байта
chetnost = (byte.count("1")) # Вычисленное значение четности байта для сравнения со считанным
if chetnost in chet :
bit_chetnosti = "0"
if chetnost in nechet :
bit_chetnosti = "1"
if code[i98] != bit_chetnosti : # Если прочитанный с ленты и вычисленный биты четности не совпадают
znak = " ?"
else : # Если биты четности данного байта совпадают
znak = " +"
polubyte1 = polubyte[str(code[i9 : i94])]
polubyte2 = polubyte[str(code[i94 : i98])]
ks = ks + int(polubyte1) + int(polubyte2) # Прибавляем текущий байт в контрольную сумму
print(i, byte, " ", code[i98], bit_chetnosti, znak, polubyte1 + polubyte2, byte_sample[i], int(byte_sample[i]/2), file=out_file)
print(polubyte1 + polubyte2, file=out_file1)
if ((polubyte1 + polubyte2) == "0512"): # Исключаем байт конца программы из контрольной суммы (при условии, что 0512 последний байт)
ks = ks -17
print("Количество байт = ", int(len3a),)
print("Контрольная сумма = ", ks,)
print("Контрольная сумма = ", ks, file=out_file)
btime = datetime.datetime.today().strftime("%d.%m.%Y-%H.%M.%S") # Время окончания раскодировки
print()
print("Раскодирование начато в ", atime, ",", "окончено в", btime)
os.system('sleep 0.9')
os.system('play --no-show-progress --null --channels 1 synth %s sine %f' % (0.05, 1600)) # Звуковой сигнал
print("Раскодирование начато в ", atime, ",", "окончено в", btime, file=out_file)
print("Операция завершена успешно.")
os.system('sleep 0.9')
print("Листинг находится в текущем каталоге в файле ", str(outfile[0])+".txt")
os.system('sleep 0.9')
print("Отладочный листинг находится в текущем каталоге в файле ", str(outfile[0])+".decode")
os.system('sleep 0.1')
os.system('play --no-show-progress --null --channels 1 synth %s sine %f' % (0.05, 1600)) # Звуковой сигнал
os.system('sleep 0.1')
os.system('play --no-show-progress --null --channels 1 synth %s sine %f' % (0.05, 1600)) # Звуковой сигнал
print()
out_file.close() # Закрываем все файлы
out_file1.close()
wav.close()Виталий