Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1.  
  2. import sys
  3. import wave
  4. import struct
  5. import pyaudio
  6.  
  7. class AudioAnalyzer:
  8.  
  9.     def __init__(self):
  10.         # Sample width (16bites)
  11.         self.sw = -1
  12.  
  13.         # Samples per second (8000Hz)
  14.         self.sps = -1
  15.  
  16.         self.values = []
  17.         self.noise = {'max':0, 'min':0}
  18.  
  19.         self.pos_num = {0 :0x8, 1 :0x9, 2 :0x5, 3 :0x0,
  20.                         4 :0x4, 5 :0xe, 7 :0x7, 9 :0xd,
  21.                         11:0xa, 12:0x1, 31:0x2, 39:0xc,
  22.                         58:0xf, 60:0x6, 61:0xb, 95:0x3}
  23.  
  24.         self.signatures = {}
  25.  
  26.  
  27.     def to_samp(self, secs):
  28.         return int(self.sps*secs)
  29.  
  30.  
  31.     def load_file(self, filename):
  32.         wav = wave.open(filename, 'rb')
  33.        
  34.         self.sw = wav.getsampwidth()
  35.         self.sps = wav.getframerate()
  36.  
  37.         wav.rewind()
  38.         while True:
  39.             frames = wav.readframes(self.sps)
  40.             if not frames:
  41.                 break
  42.  
  43.             for i in range(0, len(frames), self.sw):
  44.                 self.values.append(struct.unpack('h', frames[i:i+2])[0])
  45.         wav.close()
  46.  
  47.    
  48.     def play(self, sample):
  49.         p = pyaudio.PyAudio()
  50.         stream = p.open(format=p.get_format_from_width(self.sw),
  51.                 channels=1,
  52.                 rate=self.sps,
  53.                 output=True)
  54.         stream.write(sample)
  55.         stream.stop_stream()
  56.         stream.close()
  57.  
  58.  
  59.     ''' Takes the information needed to recognize a silence
  60.        segment. This will be used to split
  61.        the audio in the different components.
  62.        .- offset in seconds (float)
  63.        .- size in seconds (float)
  64.    '''
  65.     def set_silence_sample(self, offset, size):
  66.         end = offset + size + 1
  67.         silence_segment = self.values[offset:end]
  68.  
  69.         # "100" is an estimated error
  70.         self.noise['max'] = max(silence_segment) + 200
  71.         self.noise['min'] = min(silence_segment) - 200
  72.  
  73.         print(self.noise)
  74.  
  75.  
  76.     ''' This method return the offset and size of the
  77.        next silence segment starting from offset.
  78.        .- offset in seconds (float)
  79.        .- minimal silence segmente size in seconds (float)
  80.    '''
  81.     def next_silence(self, offset, min_size):
  82.        
  83.         index = offset
  84.         silence = {'offset':-1, 'size':0}
  85.  
  86.         while True:
  87.             try:
  88.                 value = self.values[index]
  89.             except IndexError:
  90.                 break
  91.            
  92.             if (value > (self.noise['min'])) and (value < (self.noise['max'])):
  93.                 if silence['offset'] == -1:
  94.                     silence['offset'] = index
  95.                 silence['size'] += 1
  96.            
  97.             elif silence['size'] > min_size:
  98.                 break
  99.  
  100.             else:
  101.                 silence['offset'] = -1
  102.                 silence['size'] = 0
  103.  
  104.             index += 1
  105.  
  106.         if (silence['offset'] != -1) and (silence['size'] > min_size):
  107.             return silence
  108.         return None
  109.  
  110.  
  111.     def split(self, start_offset, silence_min_size):
  112.         offset = start_offset
  113.         size = 0
  114.         results = []
  115.         silence = self.next_silence(start_offset, silence_min_size)
  116.         while silence:
  117.             if offset != silence['offset']:
  118.                 audio = {'offset':(offset + size),
  119.                          'size'  :(silence['offset'] - (offset + size))}
  120.                 results.append(audio)
  121.            
  122.             offset = silence['offset']
  123.             size = silence['size']
  124.  
  125.             silence = self.next_silence((offset + size), silence_min_size)
  126.  
  127.         return results
  128.  
  129.  
  130.     def get_signature(self, offset, size):
  131.         signature = []
  132.         signature_len = 10
  133.  
  134.         segment = self.values[offset:(offset+size)]
  135.  
  136.         interval_size = size/signature_len
  137.         for index in range(0, signature_len):
  138.             interval = segment[index*interval_size:(index+1)*interval_size]
  139.            
  140.             tmp = [v for v in interval if v >= 0]
  141.             top = sum(tmp)/len(tmp)
  142.  
  143.             tmp = [v for v in interval if v < 0]
  144.             bottom = sum(tmp)/len(tmp)
  145.  
  146.             signature.append(top - bottom)        
  147.  
  148.         return tuple(signature)
  149.  
  150.  
  151.     def signature_to_number(self, signature):
  152.         result = None
  153.        
  154.         best = None
  155.         for _signature in self.signatures:
  156.             tmp = []
  157.             for i in range(0, len(signature)):
  158.                 tmp.append(abs(signature[i] - _signature[i]))
  159.  
  160.             if best == None:
  161.                 best = tmp
  162.                 result = _signature
  163.             else:
  164.                 points = 0
  165.                 for i in range(0, len(signature)):
  166.                     if tmp[i] < best[i]:
  167.                         points += 1
  168.                     else:
  169.                         points -= 1
  170.  
  171.                 if points > 0:
  172.                     best = tmp
  173.                     result = _signature
  174.  
  175.         return self.signatures[result]
  176.  
  177.  
  178. if __name__ == '__main__':
  179.  
  180.     if len(sys.argv) < 2:
  181.         print('$ {0} <audio_file.wav>'.format(sys.argv[0]))
  182.         sys.exit(-1)
  183.  
  184.     solution = AudioAnalyzer()
  185.  
  186.     print('loading file ...')
  187.     solution.load_file(sys.argv[1])
  188.  
  189.     print('Setting silence sample ...')
  190.     solution.set_silence_sample(int(solution.sps*11.5), int(solution.sps*6.5))
  191.  
  192.     ns = solution.next_silence(int(solution.sps*18.4), int(solution.sps*0.10))
  193.     print('next silence - offset {0} - size {1} - end {2}'.format(ns['offset'],
  194.                                                                   ns['size'],
  195.                                                                  (ns['offset'] + ns['size'])))
  196.     print('Spliting audio ...')
  197.     components = solution.split(0, int(solution.sps*0.13))
  198.    
  199.     components = components[2:]
  200.  
  201.     print('Calculating reference signatures ...')
  202.     index = 0
  203.     for component in components:
  204.         if component['size'] < 1000:
  205.             print('Bad segment :S')
  206.             continue
  207.         signature = solution.get_signature(component['offset'], component['size'])
  208.         if index in solution.pos_num:
  209.             number = solution.pos_num[index]
  210.             solution.signatures[signature] = number
  211.         if index > 95:
  212.             break
  213.         index += 1
  214.  
  215.     numbers = []    
  216.  
  217.     print('------------------------------------------------------')
  218.     index = 0
  219.     for component in components:
  220.         print('({0})'.format(index))
  221.        
  222.         print('size {0}'.format(component['size']))
  223.         print('beginning {0} - end {1}'.format(component['offset'],
  224.                                               (component['offset'] + component['size'])))
  225.         if component['size'] < 1000:
  226.             print('Bad segment :S')
  227.             continue
  228.         signature = solution.get_signature(component['offset'], component['size'])
  229.         print(signature)
  230.            
  231.         number = solution.signature_to_number(signature)
  232.         numbers.append(number)
  233.         print(number)
  234.  
  235.         index += 1
  236.         print('------------------------------------------------------')
  237.    
  238.     fd = open('result.hex', 'a+')
  239.    
  240.     for i in range(0, len(numbers), 2):
  241.         byte = struct.pack('B', (numbers[i] << 4) + numbers[i+1])
  242.         fd.write(byte)
  243.    
  244.     fd.close()