Раскодировщик работает под управлением 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()
Виталий