"""Lambda handler for defining audio track similarity.""" import os import time import uuid import ffmpy import soundfile as sf import numpy as np DEFAULT_TMP_DIR = os.environ.get('DEFAULT_TMP_DIR', '/Users/maximov/Desktop/tmp') # without ending backslash FFMPEG_PATH = os.environ.get('FFMPEG', '/usr/local/bin/ffmpeg') PCM_S16LE_CODEC = '-acodec pcm_s16le -ar 16000 -ac 1' DELTA = 0.000000000000001 assert DEFAULT_TMP_DIR def time_usage(func): """Print elapsed execution time.""" def wrapper(*args, **kwargs): beg_ts = time.time() retval = func(*args, **kwargs) end_ts = time.time() print("elapsed time: %f" % (end_ts - beg_ts)) return retval return wrapper def transcode_to_pcm(input_path): """Transcode input file to pcm encoded audio file by ffmpeg. Args: input_path (str): input file path Result: str: output wav file path. File has unique filename. """ output_path = '{}/{}.wav'.format(DEFAULT_TMP_DIR, uuid.uuid4()) ff = ffmpy.FFmpeg( executable=FFMPEG_PATH, # add path to executable ffmpeg inputs={input_path: None}, outputs={output_path: PCM_S16LE_CODEC} ) ff.run() return output_path def get_fft(file_path): """Calculate Fast Fourier transform. Args: file_path (str): file path to standardized pcm. Result: np.array: Normalized frames. """ normalized_amplitudes, samplerate = sf.read(file_path, always_2d=False) number_of_subarrays = int(normalized_amplitudes.size / 1000) frames = np.array_split(normalized_amplitudes, number_of_subarrays) transcoded_fft = [] for f in frames: transcoded_frame = np.fft.fft(f) result = [np.complex(DELTA, DELTA) if f == np.complex(0, 0) else f for f in transcoded_frame] transcoded_fft.append(result) return transcoded_fft @time_usage def handler(event, context): """Handler method.""" transcoded_fft = get_fft(transcode_to_pcm(event['output_path'])) source_fft = get_fft(transcode_to_pcm(event['source_path'])) result = [] for s, t in zip(transcoded_fft, source_fft): result.append(np.corrcoef(s, t)[1, 0]) return {event['output_path']: np.std(result)} if __name__ == '__main__': events = [ { 'output_path': '/Users/maximov/Desktop/tmp/b-flac.flac', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' }, { 'output_path': '/Users/maximov/Desktop/tmp/b-mp3.mp3', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' }, { 'output_path': '/Users/maximov/Desktop/tmp/b-m4.m4a', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' }, { 'output_path': '/Users/maximov/Desktop/tmp/b-wav.wav', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' }, { 'output_path': '/Users/maximov/Desktop/tmp/b-1-muted.wav', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' }, { 'output_path': '/Users/maximov/Desktop/tmp/b-5-muted.wav', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' }, { 'output_path': '/Users/maximov/Desktop/tmp/b-001-muted.wav', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' }, { 'output_path': '/Users/maximov/Desktop/tmp/b-005-muted.wav', 'source_path': '/Users/maximov/Desktop/tmp/b.wav' } ] result_correlation = [] for e in events: result_correlation.append(handler(e, None)) for item in result_correlation: print(item)