-
Notifications
You must be signed in to change notification settings - Fork 0
/
inaudibleFreqsFromWav.py
166 lines (155 loc) · 6.02 KB
/
inaudibleFreqsFromWav.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import wave
import struct
from collections import Counter
import numpy as np
#try to reduce this to just one math library. Find logbase2 function in cmath or pi and exp and stuff in math
import cmath
import math
def main():
#uppercase characters array
cap = ['~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '{', '}', '|', ':', '"', '<', '>', '?'];
#lowercase characters array
low = ['`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '[', ']', '\\', ';', '\'', ',','.', '/'];
# Each character is assigned a frequency in hz here.
enum = {
0 : '0',
1 : '1',
2 : '2',
3 : '3',
4 : '4',
5 : '5',
6 : '6',
7 : '7',
8 : '8',
9 : '9',
10: 'a',
11: 'b',
12: 'c',
13: 'd',
14: 'e',
15: 'f',
}
def isCapital(letter):
if (letter.islower()): #if it is an uppercase letter
return letter.upper();
elif (letter in low): #or if it is in the caps array
return cap[low.index(letter)];
print(letter)
return ''
def determineCharRep(fs, freq):
step_size = 202
letter = (int((freq-18000)/step_size))-1
print ('Letter in determineCharRep: ', letter)
return enum.get(letter, '?')
#*****************************************************************************************
# This is our implementation of the dft
#*****************************************************************************************
def compute_dft(input):
# Number of inputs
n = len(input)
output = [complex(0)] * n
for k in range(n): # For each output element
# Reset output
s = complex(0)
for t in range(n): # For each input element
# input times e^(-2(pi)i*t*k/n)
s += input[t] * cmath.exp(-2j * cmath.pi * t * k / n)
# Set bin
# Not sure if we need to take abs value yet. Will switch if necessary.
output[k] = s
return output
#*****************************************************************************************
# This is our implementation of the fft
#*****************************************************************************************
def compute_fft(x):
#N is sample length or number of samples
#x is our input array aka our signal
N = len(x)
if N <= 1: return x
#divide and conquer portion of algorithm. Divide evens and odds and do fft on both halves
even = compute_fft(x[0::2])
odd = compute_fft(x[1::2])
# x(n) * e^-i2pikn/N in practical cryptography site.
T= [odd[k]*cmath.exp(-2j*pi*k/N) for k in range(N//2)]
#this represents the real portion of N + this represents the imaginary portion of N
return np.array([even[k] + T[k] for k in range(N//2)] + [even[k] - T[k] for k in range(N//2)])
#*****************************************************************************************
# This is an optimized implementation of the fft. Same (O) as our fft but use constants
# instead of calculations in the loop
#*****************************************************************************************
def compute_fft_numpy(input):
return np.fft.fft(input);
def filterResultString(stringOfResults):
import re
#definitely keep
prevChar = ''
guessString = ''
alternativeString = ''
#might keep
semiFinalString = ''
finalString = ''
return re.sub(r'.*``+([^`]+\w*)``+.*', r'\1', stringOfResults)
#**Open the Wav in read mode*****************************************************************
waveFile = wave.open('output.wav', 'r')
#****************************************************************************************
# Set our Variables. Look in useful info below to find variable meanings in more depth.
#***************************Set directly by Wav FIle info************************************
(channels,samp_width,fs,num_frames,compression_type, compression_name) = waveFile.getparams()
frames = waveFile.readframes(num_frames * channels)
#***************************Variables for intermediary calculations******************************
N = int(num_frames/channels) # Total number of samples?
data = np.asarray(struct.unpack_from("%dh" % num_frames * channels, frames)) #Grab data from Wave to be put into FFT
#**************************Variables used for final calculation*****************************************************
freqs = np.fft.fftfreq(fs, 1/fs)
#NEED TO SPLIT UP DATA HERE BEFORE DOING FFT
print('data')
print(data)
print('num_frames')
print(num_frames)
print('fs')
print(fs)
splitData = np.split(data, num_frames/fs)
# #Now we need to operate on each splite piece of the data.
amplitudes = []
for x in range(len(splitData)):
if (float.is_integer(math.log2(len(splitData[x])))):
amplitudes.append(1/N * abs(compute_fft(splitData[x])))
else:
amplitudes.append(1/N * abs(compute_fft_numpy(splitData[x])))
#*******************************Print out the results************************************************
stringOfResults = ""
count = 0
prevLetter = ''
for i in range(len(amplitudes)):
# We are getting the maximum aplitude over the duration of time.
maxIndex = np.argmax(amplitudes[i])
# Use Symmetry to get it at right index.
if(maxIndex > fs):
maxIndex -= fs
# print(determineCharRep(fs,abs(freqs[maxIndex])))
stringOfResults += determineCharRep(fs,abs(freqs[maxIndex]))
print ('Current String Of Results: ', stringOfResults)
print('stringOfResults')
print(stringOfResults)
stringOfResults = filterResultString(stringOfResults);
print('stringOfResults')
print(stringOfResults)
prevLetter = ''
finalResult = ''
for letter in stringOfResults:
if (prevLetter == letter):
count +=1
if(count > 3):
prevLetter = isCapital(letter)
count = 1
else:
for x in range(count):
finalResult += prevLetter
prevLetter = letter
count = 1
for i in range(count):
finalResult += prevLetter
print('finalResult')
print(finalResult)
if __name__ == "__main__":
main()