python - machine learning/data mining for pattern data finding -


a have problems in audio network (i work ip audio) - time time have short gaps in audio stream. have logger record streams. i've write small script python , ffmpeg (and borrowed javascript visualizing :)) find gaps in logger mp3 files. it's better nothing have lot of false detections - it's quite annoying to check results manually - script finds 20 200 gaps per hour , 1-10 gaps caused fault - others short term low audio level in songs, speech, etc. i'm looking high level machine learning/data mining mechanism check gaps automatically leave want. can provide lot of "true" gaps (array data) , "false" gaps teach machine , after want feed data stamp gap inside compare "true" gap or not. can recommend fastest solution? note python thing can write little. :/ @ moment code of gap searching following. finds gaps duration more gap_min ms , less gap_max ms in mp3 file or folder files.

import numpy np import subprocess, os, sys import ntpath  tolerance=150#100 gap_min=0.007#0.021 gap_max=0.035#0.03 sample_rate=48000 gap_file_duration=3#duration of output mp3 files gaps ffmpeg_path=r'/applications/ffmpeg' temp_folder=r'/users/user/downloads/' result_folder=r'/users/user/downloads/tmp/' target_lufs=-9#in lufs  def samples_to_timecode(samples):     return '{0:02d}:{1:02d}:{2:02d}.{3:02d}'.format(int(samples / (3600*sample_rate)),                                                     int(samples / (60*sample_rate) % 60),                                                     int(samples / sample_rate % 60),                                                     int(samples % sample_rate))  def timecode_to_samples(timecode):     return sum(f * int(t) f,t in zip((3600*sample_rate, 60*sample_rate, sample_rate, 1), timecode.split(':')))  def seconds_to_timecode(seconds):     return '{0:02d}:{1:02d}:{2:03f}'.format(int(seconds / (3600)),                                                     int(seconds / (60) % 60),                                                     seconds % 60)#,                                                     #int(seconds % 1000 % 60))  def analyze_bin_file(source_file):     print('analizing start...')     data = np.memmap(source_file, dtype='h', mode='r')     zero_indexes=np.where(np.logical_and(data>=-tolerance, data<=tolerance))     gap_start=none     gaps_array=[]     in range(len(zero_indexes[0])-1):         if zero_indexes[0][i+1]-zero_indexes[0][i] == 1:             if not gap_start: gap_start=i         else:             if gap_start:                 if ((zero_indexes[0][i]-zero_indexes[0][gap_start]) >= (gap_min*sample_rate)) , ((zero_indexes[0][i]-zero_indexes[0][gap_start]) <= (gap_max*sample_rate)):                     gaps_array.append([float(zero_indexes[0][gap_start])/sample_rate,                           float(zero_indexes[0][i])/sample_rate,                           samples_to_timecode(zero_indexes[0][gap_start]),                           round(float(zero_indexes[0][i]-zero_indexes[0][gap_start])/sample_rate,3)])                     print('gaps found: %s' % len(gaps_array))                 gap_start=none     os.remove(source_file)#for reasons works badly in windows. comment line if cause problem. should delete temporary bin files manually after that.     print('analizing done!')     return gaps_array  def execute_cmd(cmd):     p = subprocess.popen(cmd , shell=true, stdout=subprocess.pipe, stderr=subprocess.pipe)     out, err = p.communicate()     return out.rstrip(), err.rstrip(), p.returncode  def prepare_bin_file(source_file):     print('start preparing binary file...')     result_file_path=temp_folder+ntpath.basename(source_file)+'.bin'     result=execute_cmd('{0} -i {1} -ar {4} -af volume={3} -ac 1 -map 0:a -c:a pcm_s16le -y -f data {2}'.format(ffmpeg_path,                                                                                          source_file,                                                                                          result_file_path,                                                                                         volume,                                                                                         sample_rate))     if result[2] == 0:         print('preparing done!')         return result_file_path     else:         print('error occures while preparing!')  def cut_gaps(mp3_file,gaps_array):     print('cutting file {0} start...'.format(mp3_file))     result_files=[]     path_list = mp3_file.split(os.sep)     gap in range(len(gaps_array)):         gap_start=seconds_to_timecode(gaps_array[gap][0]-float(gap_file_duration)/2)         gap_duration=gap_file_duration+gaps_array[gap][3]         result=execute_cmd('{0} -y -i {1} -ss {2} -t {3} -c:a copy {4}'.format(ffmpeg_path,                                                                              mp3_file,                                                                              gap_start,                                                                              gap_duration,                                                                              result_folder+path_list[-2]+os.sep+'mp3'+os.sep+ntpath.basename(mp3_file)+'.{0:03d}'.format(gap)+'.mp3'))         #print('save bin data file {0} of {1} {2}'.format(gap+1, len(gaps_array), 'ok' if (result_bin[-1] == 0) else 'error'))         #print(result_bin)         result_files.append(ntpath.basename(mp3_file)+'.{0:03d}'.format(gap)+'.mp3')         print('cutting file {0} of {1} {2}'.format(gap+1, len(gaps_array), 'ok' if (result[-1] == 0) else 'error'))     print('cutting done!')     return result_files  def make_report(source_file, gaps_array, cut_files):     path_list = source_file.split(os.sep)     report=open(result_folder+path_list[-2]+os.sep+ntpath.basename(source_file)+'.html','w')     report.write('<!doctype html><html lang=""><head></head><html><body><script src="https://cdnjs.cloudflare.com/ajax/libs/wavesurfer.js/1.1.2/wavesurfer.min.js"></script>')     report.write('<div>file {0} analizing report<br>'.format(source_file))     report.write('searching parameters:<br>gap minimum {0} second<br>gap maximum {1} second<br>tolerance value {2}<br>analyze volume {3} db<hr><hr></div>'.format(gap_min,                                                                                                                                               gap_max,                                                                                                                                               tolerance,                                                                                                                                              volume))     if len(gaps_array) > 0:         gap_no in range(len(gaps_array)):             report.write('<div>gap no {0}<br>gap start {1}<br>gap duration {2}ms</div>'.format(gap_no,                                                                                gaps_array[gap_no][2],                                                                                gaps_array[gap_no][3]*1000))             html="""             <div id='waveform""" + str(gap_no) + """'></div>  <div style='text-align: center'>   <button class='btn btn-primary' onclick='wavesurfer""" + str(gap_no) + """.playpause()'>     <i class='glyphicon glyphicon-play'></i>     play   </button>    <p class='row'>     <div class='col-xs-1'>       <i class='glyphicon glyphicon-zoom-in'></i>     </div>      <div class='col-xs-10'>       <input id='slider""" + str(gap_no) + """' type='range' min='1' max='4000' value='1' style='width: 100%' />     </div>      <div class='col-xs-1'>       <i class='glyphicon glyphicon-zoom-out'></i>     </div>   </p> </div>             """             report.write(html)             script="""             <script> var wavesurfer""" + str(gap_no) + """ = wavesurfer.create({   container: '#waveform""" + str(gap_no) + """',   wavecolor: 'red',   progresscolor: 'purple' });  wavesurfer""" + str(gap_no) + """.load('./mp3/""" + cut_files[gap_no] + """');  var slider""" + str(gap_no) + """ = document.queryselector('#slider""" + str(gap_no) + """');  slider""" + str(gap_no) + """.oninput = function () {   var zoomlevel = number(slider""" + str(gap_no) + """.value);   wavesurfer""" + str(gap_no) + """.zoom(zoomlevel); }; </script>             """             report.write(script)     else:         report.write('<div>no gaps found!</div>')     report.write('</body></html>')     report.close()  def normalize_file(source):     print('analizing integrated loudness...')     result = execute_cmd('{0} -nostats -i {1} -filter_complex ebur128 -f null -'.format(ffmpeg_path,                                                                                          source))     if result[-1] == 0:         summary_index=str(result[1][-255:]).rfind('summary:')         summary_list=str(result[1][-255:][summary_index:]).split()         i_lufs = float(summary_list[summary_list.index('i:') + 1])         gainlog = -(i_lufs - target_lufs)         volume = 10 ** (gainlog / 20)         print('analizing complete. i= {0} lufs. volume change value={1}.'.format(i_lufs, volume))     else:         print('error!')     return volume  def run(source):     if os.path.isfile(source) or os.path.isdir(source):         path_list = source.split(os.sep)         if not os.path.isdir(result_folder+path_list[-2]):             os.makedirs(result_folder+path_list[-2])         if not os.path.isdir(result_folder+path_list[-2]+os.sep+'mp3'):             os.makedirs(result_folder+path_list[-2]+os.sep+'mp3')     else:         print('error! file of folder {0} not found!'.format(source))     if os.path.isfile(source):         global volume         volume=normalize_file(source)         bin_file=prepare_bin_file(source)         gaps_array=analyze_bin_file(bin_file)         if len(gaps_array):             cut_files=cut_gaps(source, gaps_array)             make_report(source, gaps_array, cut_files)         else:             make_report(source, gaps_array, cut_files=[])     elif os.path.isdir(source):         file in os.listdir(source):             if file.endswith(".mp3"):                 print(source ,file)                 run(source+os.sep+file)  src=r'/users/user/downloads/2016-08-02' if len(sys.argv) > 1:     run(sys.argv[1]) else:     run(src)     

the result html file waveforms. result works in firefox browser. false gaps: example of false gap 1 true gaps: example of true gap 1

update. because algorithm sensitive volume level, i've added volume normalization before analyzing data. doesn't apply output files - it's normalize data before being analyzed.


Comments