From 971e0b80387e04671cf766c6d808d886fbfe2ccd Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 21 Jul 2022 23:36:47 +0200 Subject: [PATCH] Initial Commit --- WAV2TAP.py | 366 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 WAV2TAP.py diff --git a/WAV2TAP.py b/WAV2TAP.py new file mode 100644 index 0000000..f6a1678 --- /dev/null +++ b/WAV2TAP.py @@ -0,0 +1,366 @@ +from tkinter import * +from tkinter import filedialog +from random import * +from scipy.io import wavfile #pip install scipy +import matplotlib.pyplot as plt + +import os + + +PlotErrors = False + +def wavfile_to_examples(wav_file): + """Convenience wrapper around waveform_to_examples() for a common WAV format. + + Args: + wav_file: String path to a file, or a file-like object. The file + is assumed to contain WAV audio data with signed 16-bit PCM samples. + + Returns: + See waveform_to_examples. + """ + try: + sr, wav_data = wavfile.read(wav_file) + except IOError: + print("Error reading WAV file!") + print("The specified WAV file type is not supported by scipy.io.wavfile.read()") + sys.exit(1) + + #if wav_data.dtype != np.int16: + # raise TypeError('Bad sample type: %r' % wav_data.dtype) + samples = wav_data / 32768.0 # Convert to [-1.0, +1.0] + return samples, sr + + +def DecodeTime(aT): + if aT > (1/250): # Silent + Bit = 'S' + else: + if aT > (1/800): + Bit = 'T' + else: + if aT > (1/1500): + Bit = '1' + else: + if aT > (1/3000): + Bit = '0' + else: + Bit = 'E' + return Bit + +def GetName(aBlock): + if aBlock[0] == 1: + NameBlock = [] + if aBlock[1] == 0xD3: # BASIC + for Byte in aBlock[4:12]: + if Byte != 0: + NameBlock.append(Byte) + else: # CHAOS + for Byte in aBlock[1:9]: + if Byte != 0: + NameBlock.append(Byte) + Name = ''.join([''.join(chr(ch)) for ch in NameBlock]) + Name.replace('&','n') + else: + Name = '' + print(Name) + return Name.strip() + +def WriteTAB(aBlocks, aFilename): + with open(aFilename,'wb') as TAB_file: + TAB_file.write(b'\xC3KC-TAPE by AF. ') # C3 4B 43 2D 54 41 50 45 20 62 79 20 41 46 2E 20 + #Block = [b''.join(ch) for ch in aBlocks[0]] + for Block in aBlocks: + Bytes = bytes(Block[0:-1]) + TAB_file.write(Bytes) + +def WriteTABs(aBlocks, aPath): + Index = 1 + NewFile = False + Filename = 'Errors.TAP' + TAB_file = open(Filename,"wb") + TAB_file.close() + for Block in aBlocks: + if not (len(Block) == 130): + print('Bad Block') + if Block[0] == 1: + Filename = os.path.join(aPath,str(Index).zfill(3) + '_' + GetName(Block) + '.TAP') + Index = Index + 1 + NewFile = True + if NewFile: + if TAB_file.closed: + TAB_file = open(Filename,"wb") + else: + TAB_file.close() + TAB_file = open(Filename,"wb") + NewFile = False + if not TAB_file.closed: + Bytes = bytes(Block) + TAB_file.write(Bytes) + if Block[0] == 0xFF: + TAB_file.close() + + + +def WriteRAW(aBlocks, aFilename): + with open(aFilename,'wb') as RAW_file: + for Block in aBlocks: + try: + Bytes = bytes(Block) + except: + print(Block) + RAW_file.write(Bytes) + + +#Block = [1, 211, 211, 211, 72] +#Block2 = bytes(Block) #[b''.join(bytes(abyte)) for abyte in Block] + +fenster = Tk() +fenster.filename = "" +fenster.filename = filedialog.askopenfilename(initialdir = "", title = "Select file", filetypes =(("wav files","*.wav"),("all files","*"))) +print(fenster.filename) +filename = fenster.filename +fenster.destroy() + +if os.path.exists(filename) and not (os.path.isdir(filename)): + File = os.path.splitext(filename)[0] + Ext = os.path.splitext(filename)[1] + OutputFile = File + ".TAP" + RawFile = File + ".RAW" + + Samples, Rate = wavfile_to_examples(filename) + #print(Samples[1:1000,0]) + + + print('Samplerate: ',Rate) + AmplitudeL = 0; + BestChannel = 0; + for data in Samples[0:4410000]: #100s + if abs(data[0]) > AmplitudeL: + AmplitudeL = abs(data[0]); + print('Amplitude Links:',AmplitudeL) + AmplitudeR = 0; + for data in Samples[0:4410000]: #100s + if abs(data[1]) > AmplitudeR: + AmplitudeR = abs(data[1]); + print('Amplitude Rechts:',AmplitudeR) + if AmplitudeR > AmplitudeL: + BestChannel = 1; + + Bitstream = [] + Periode1 = 0 + Periode2 = 0 + LastData1 = 0 + LastData2 = 0 + LastData3 = 0 + LastData4 = 0 + LastData5 = 0 + LastData = 0 + NextData = 0 + Min1 = 1.0 + Max1 = -1.0 + + Min2 = 1.0 + Max2 = -1.0 + + CalcSpeedError = True; + Speedfaktor = 1.0 + + EinsCount = 0 + EinsTime = 0.0 + + UseDecoder = 0 + EnableDecoder1 = True # Damit er nicht 2x bei der steigenden Flanke auslöst + EnableDecoder2 = True + + + SampeNr = -1 + for data in Samples: + SampeNr = SampeNr + 1 + Periode1 = Periode1 + 1 + Periode2 = Periode2 + 1 + Ellongation = data[BestChannel] + if Min1 > Ellongation: + Min1 = Ellongation + if Max1 < Ellongation: + Max1 = Ellongation + Zero1 = Min1 + ((Max1 - Min1) / 2) + + if Min2 > Ellongation: + Min2 = Ellongation + if Max2 < Ellongation: + Max2 = Ellongation + Zero2 = Min2 + ((Max2 - Min2) / 2) + + LastData = (LastData3 + LastData4 + LastData5) / 3 + NextData = (Ellongation + LastData1 + LastData2) /3 + + if (Periode2 > 8) and (Zero2 > LastData) and (Zero2 < NextData): + EnableDecoder2 = True + if (EnableDecoder2) and (Periode2 > 8) and (Zero2 < LastData) and (Zero2 > NextData): + T = (Periode2 / Rate) * Speedfaktor + Periode2 = 0 + EnableDecoder2 = False + EnableDecoder1 = True + Min2 = Ellongation + Max2 = Ellongation + Bit = DecodeTime(T); + if (UseDecoder == 0) and (Bit == 'T'): + UseDecoder = 2 + #print('Decoder 2') + if UseDecoder == 2: + Bitstream.append([Bit,SampeNr-2]) # Nullstelle Speichern + + if (Periode1 > 8) and (Zero1 < LastData) and (Zero1 > NextData): + EnableDecoder1 = True + if (EnableDecoder1) and (Periode1 > 8) and (Zero1 > LastData) and (Zero1 < NextData): + T = (Periode1 / Rate) * Speedfaktor + #print(Periode, Min, Max, Zero, LastData1, Ellongation ) + Periode1 = 0 + EnableDecoder1 = False + EnableDecoder2 = True + Min1 = Ellongation + Max1 = Ellongation + Bit = DecodeTime(T); + if (UseDecoder == 0) and (Bit == 'T'): + UseDecoder = 1 + #print('Decoder 1') + if UseDecoder <= 1: + Bitstream.append([Bit,SampeNr-2]) # Nullstelle Speichern + if Bit == '1': + EinsCount = EinsCount + 1 + EinsTime = EinsTime + T + if (EinsCount == 50): + UseDecoder = 0 + EnableDecoder1 = True + EnableDecoder2 = True + if (CalcSpeedError): + Speedfaktor = (1/1200) / (EinsTime / EinsCount) + CalcSpeedError = False + else: + EinsCount = 0 + EinsTime = 0.0 + + LastData5 = LastData4 + LastData4 = LastData3 + LastData3 = LastData2 + LastData2 = LastData1 + LastData1 = Ellongation + + print('Speedfaktor = ', Speedfaktor) + #print(Bitstream[0:100]) + + EinsCount = 0; + FileFound = False + Blocknummer = 1 + Bytenummer = 0 + Block = [] + Blocks = [] + Byte = 0 + Bitcounter = 0; + BlockFound = False; + BitstreamIndex = -1; + for Bit in Bitstream: + BitstreamIndex = BitstreamIndex + 1 + if (Bit[0] == '1') : + EinsCount = EinsCount + 1 + if (Bitcounter < 8): + #Byte = Byte | (1 << Bitcounter) # hier stehen die ersten bits richtig wenn nur 7bit + Byte = (Byte >> 1) | 0x80 # hier stehen die letzten bits richtig wenn nur 7bit + Bitcounter = Bitcounter + 1 + else: + if (Bit[0] != 'T'): + EinsCount = 0 + if Bit[0] == '0': + Byte = (Byte >> 1) # hier stehen die letzten bits richtig wenn nur 7bit + Bitcounter = Bitcounter + 1 + #if Bit[0] == 'E': + # print('Fehlerhaftes Bit') + #if Bit[0] == 'S': + # print('Stille') + + + if (EinsCount > 300) and (Bit[0] == 'T'): #Newfile + FileFound = True; + print('File Found') + File = [] + Block = [] + BlockFound = False + Blocknummer = 1 + Bytenummer = 0 + IndexFehlerhaft = 0 + if FileFound: + if ((Bytenummer == 130)): + if (Blocknummer == 1): + Name = [''.join(chr(ch)) for ch in Block[1:12]] + print(''.join(Name)) + #print(chr(Block[1])) + Blocks.append(Block) + summe = 0 + for byte in Block[1:-1]: + summe = summe + byte + summe = summe & 0xFF + if summe != Block [-1]: + print('%d Summe %d NOK Read %d' % (Block [0], summe, Block [-1])) + print(Block) + if (IndexFehlerhaft > 0) and (IndexFehlerhaft < 129): + print('Fehlerhaftes Byte konnte identifiziert werden', IndexFehlerhaft) + print('Gelesen wurde: ', Block[IndexFehlerhaft-1]) + Block[IndexFehlerhaft-1] = (Block[IndexFehlerhaft-1] + ((Block[-1] - summe) & 0xFF)) & 0xFF + print('Sollte laut Summe sein: ', Block[IndexFehlerhaft-1]) + summe = 0 + for byte in Block[1:-1]: + summe = summe + byte + summe = summe & 0xFF + if summe == Block [-1]: + print('Korrigiert!') + else: + print('Mehr als einn Byte Fehlerhaft') + + else: + print('%d OK' % Block [0]) + #Name = [''.join(chr(ch)) for ch in Block[1:-1]] + #print(''.join(Name)) + if Block[0] == 0xFF: + FileFound = False + Block = [] + Blocknummer = Blocknummer + 1; + Bytenummer = 0 + IndexFehlerhaft = 0 + BlockFound = False + #print('Block ',Blocknummer) + if (not BlockFound) and (EinsCount > 50) and (Bit[0] == 'T'): # neuer Block + Bitcounter = 0 + Bytenummer = 0 + Byte = 0 + BlockFound = True + else: + if Bit[0] == 'T' and BlockFound: + Block.append(Byte & 0xFF) + Bytenummer = Bytenummer + 1; + Byte = 0 + if Bitcounter != 8: + print('Fehlerhafte Bytelänge %d im Block %d und Byte %d' % (Bitcounter,Blocknummer,Bytenummer)) + if IndexFehlerhaft == 0: + IndexFehlerhaft = Bytenummer + else: + IndexFehlerhaft = -1 + Bytelaenge = round(11*Rate/1200) + Stuetzstellen = [Bitstream[X][1] for X in range(BitstreamIndex-11, BitstreamIndex+1)] + Stuetzbits = ''.join([Bitstream[X][0] for X in range(BitstreamIndex-11, BitstreamIndex+1)]) + #print(Stuetzstellen) + if PlotErrors: + plt.plot([X for X in range((Bit[1]-Bytelaenge),(Bit[1]))],Samples[(Bit[1]-Bytelaenge):(Bit[1]),BestChannel], "-b" , label=(('1/%d' % round(1200*Speedfaktor))+ Stuetzbits)) + plt.plot(Stuetzstellen, [Samples[X,BestChannel] for X in Stuetzstellen], "or")# [Samples[Y,BestChannel] for Y in Bitstream[BitstreamIndex-11: BitstreamIndex+1][1]], "or") + plt.legend(loc='upper right') + plt.show() + Bitcounter = 0 + #if Bit[0] == 'S': + # FileFound = False; + #print(Blocks) + #WriteTAB(Blocks, OutputFile) + WriteRAW(Blocks, RawFile) + WriteTABs(Blocks, os.path.dirname(os.path.abspath(OutputFile))) + + +