Fingerprint audio - chromaprint and get fingerprint - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Homework (https://python-forum.io/forum-9.html) +--- Thread: Fingerprint audio - chromaprint and get fingerprint (/thread-17468.html) |
Fingerprint audio - chromaprint and get fingerprint - alessandro87gatto - Apr-12-2019 Hi everyone, as written in the presentation, I'm new to the forum. I'm trying to compare two audio tracks. I searched a lot on the web finding old guides like Dejavu: Dejavu Github I also found a very simple code that works in part, which is: """ Finding fingerprint and calculating simple fuzzy similarity @author [email protected] Prerequisites on Ubuntu: * Python 2.7 and pip * FFMPEG `sudo apt install ffmpeg` * AcoustID fingerprinter `sudo apt install acoustid-fingerprinter` * PyAcoustID `pip install pyacoustid` * FuzzyWuzzy `pip install fuzzywuzzy[speedup]` """ import acoustid import sys import os import chromaprint import numpy as np import matplotlib.pyplot as plt from fuzzywuzzy import fuzz DIR_DATABASE = '/Desktop/music/full' DIR_SAMPLES = '/Desktop/music/partial' def get_fingerprint(filepath): """ Get fingerprint (list of signed integer), version, duration """ duration, fp_encoded = acoustid.fingerprint_file(filepath) fp, version = chromaprint.decode_fingerprint(fp_encoded) return fp, version, duration def build_fingerprint_database(dirpath, file_ext='.mp3'): """ Build database from directory of audio files """ database = {} print('Processing {}..'.format(dirpath)) for f in os.listdir(dirpath): path = os.path.join(dirpath, f) name, ext = os.path.splitext(f) if os.path.isfile(path) and ext == file_ext: print('Getting fingerprint from database item: {}..'.format(f)) database[f], version, duration = get_fingerprint(path) return database def plot_fingerprints(db): """ Visualize fingerprints in database """ fig = plt.figure() numrows = len(db) plot_id = 1 for name, fp in db.iteritems(): # single column grid a = fig.add_subplot(numrows, 1, plot_id) imgplot = plt.imshow(get_fingerprint_bitmap(fp)) a.set_title(name) plot_id += 1 plt.show() def get_fingerprint_bitmap(fp): """ Plot list of uint32 as (32, len(list)) bitmap """ bitmap = np.transpose(np.array([[b == '1' for b in list('{:32b}'.format(i & 0xffffffff))] for i in fp])) return bitmap if __name__ == '__main__': # load database and samples database = build_fingerprint_database(DIR_DATABASE) samples = build_fingerprint_database(DIR_SAMPLES) print("inoltro path alla funzione build_fingerprint_database") print('\n') # find best match of each samples in database for sample, sample_fp in samples.iteritems(): print('Similarity score of "{}":'.format(sample)) best_match = None for name, fp in database.iteritems(): similarity = fuzz.ratio(sample_fp, fp) if not best_match or best_match['score'] < similarity: best_match = { 'score': similarity, 'name': name } print('{} {}%'.format(name, similarity)) print('Best match: {name} ({score}%)\n'.format(**best_match)) # plot database plot_fingerprints(database)It reads the audio tracks in the "/ full" directory but the function call does not work: "get_fingerprint(filepath)". Cannot find the Fingerprint attribute in the Chromaprint module. Tested with both PyCharm and terminal, with Python version 2.x and Python 3.x the result is the same. All packages are installed as commented in the code.I await your kind help RE: Fingerprint audio - chromaprint and get fingerprint - nilamo - Apr-12-2019 https://github.com/beetbox/pyacoustid/blob/master/chromaprint.py#L96 https://github.com/beetbox/pyacoustid/blob/master/chromaprint.py#L84 Those classes definitely exist. Try an interactive prompt, import chromaprint, then dir(chromaprint) . Let's see what your local version actually has available.
RE: Fingerprint audio - chromaprint and get fingerprint - alessandro87gatto - Apr-12-2019 Thanks for the reply. To make my code work, how should I change it based on your suggestion? Thank you I don't know if I did it correctly. I copied all the code that was in the link you recommended to me in the chromaprint.py system file. The file chromaprint.py, previously contained: _bg = {'black': '\033[40m', 'white': '\033[47m', 'magenta': '\033[45m', 'red': '\033[41m', 'yellow': '\033[43m', 'green': '\033[42m', 'cyan': '\033[46m', 'blue': '\033[44m', 'default': '\033[49m', 'user_default': '\033[49m' } _fg = {'black': '\033[30m', 'white': '\033[37m', 'magenta': '\033[35m', 'red': '\033[31m', 'yellow': '\033[33m', 'green': '\033[32m', 'cyan': '\033[36m', 'blue': '\033[34m', 'default': '\033[39m', 'user_default': '\033[39m' } _print = print # noqa colors = tuple(i for i in _bg.keys() if i != 'user_default') def print(*args, bg='user_default', fg='user_default'): ''' Replacement print method to print in colors *args (str): strings to be printed. Passed as if passing to built-in print method bg (str): back ''' _print(_bg[bg], _fg[fg], ' '.join(args), _bg['user_default'], _fg['user_default'], sep='') def set_default(**kwargs): ''' Sets 'user_default' colors **kwargs {fg: 'color', bg: 'color'} ''' _bg['user_default'] = _bg[kwargs.get('bg', 'user_default')] _fg['user_default'] = _fg[kwargs.get('fg', 'user_default')]The program already starts working, no more that error, it reads all the audio tracks present in both directories: full and partial, but returns the error: What am I doing wrong? How can I solve the problem? Thank youOk, it looks like I solved it. I searched google for the error: and I immediately found the problem: just change: dict.iteritems -> dict.itemsbecause we are working with Python 3 For those who want the code already working, the complete code is: """ Finding fingerprint and calculating simple fuzzy similarity Comparison of each single file in the "partial" directory with each file in the "full" directory Prerequisites: * Python 2.7 and pip * FFMPEG `sudo apt install ffmpeg` * AcoustID fingerprinter `sudo apt install acoustid-fingerprinter` * PyAcoustID `pip install pyacoustid` * FuzzyWuzzy `pip install fuzzywuzzy[speedup]` """ import acoustid import sys import os import chromaprint import numpy as np import matplotlib.pyplot as plt from fuzzywuzzy import fuzz DIR_DATABASE = '/music/full' DIR_SAMPLES = '/music/partial' def get_fingerprint(filepath): """ Get fingerprint (list of signed integer), version, duration """ duration, fp_encoded = acoustid.fingerprint_file(filepath) fp, version = chromaprint.decode_fingerprint(fp_encoded) return fp, version, duration def build_fingerprint_database(dirpath, file_ext='.mp3'): """ Build database from directory of audio files """ database = {} print('Processing {}..'.format(dirpath)) for f in os.listdir(dirpath): path = os.path.join(dirpath, f) name, ext = os.path.splitext(f) if os.path.isfile(path) and ext == file_ext: print('Getting fingerprint from database item: {}..'.format(f)) database[f], version, duration = get_fingerprint(path) return database def plot_fingerprints(db): """ Visualize fingerprints in database """ fig = plt.figure() numrows = len(db) plot_id = 1 for name, fp in db.items(): # single column grid a = fig.add_subplot(numrows, 1, plot_id) imgplot = plt.imshow(get_fingerprint_bitmap(fp)) a.set_title(name) plot_id += 1 plt.show() def get_fingerprint_bitmap(fp): """ Plot list of uint32 as (32, len(list)) bitmap """ bitmap = np.transpose(np.array([[b == '1' for b in list('{:32b}'.format(i & 0xffffffff))] for i in fp])) return bitmap if __name__ == '__main__': # load database and samples database = build_fingerprint_database(DIR_DATABASE) samples = build_fingerprint_database(DIR_SAMPLES) print("inoltro path alla funzione build_fingerprint_database") print('\n') # find best match of each samples in database for sample, sample_fp in samples.items(): print('Similarity score of "{}":'.format(sample)) best_match = None for name, fp in database.items(): similarity = fuzz.ratio(sample_fp, fp) if not best_match or best_match['score'] < similarity: best_match = { 'score': similarity, 'name': name } print('{} {}%'.format(name, similarity)) print('Best match: {name} ({score}%)\n'.format(**best_match)) # plot database plot_fingerprints(database)Rightly, we must first install all the packages listed above and modify the chromaprint.py file that is inside the path: External Libraries, <Python 3.6 (project_name), Extended Definitions, site-packages library root, Chromaprint, Chromaprint.py. The chromaprint.py file must contain the following lines: # Copyright (C) 2011 Lukas Lalinsky # (Minor modifications by Adrian Sampson.) # Distributed under the MIT license, see the LICENSE file for details. """Low-level ctypes wrapper from the chromaprint library.""" import sys import ctypes if sys.version_info[0] >= 3: BUFFER_TYPES = (memoryview, bytearray,) elif sys.version_info[1] >= 7: BUFFER_TYPES = (buffer, memoryview, bytearray,) # noqa: F821 else: BUFFER_TYPES = (buffer, bytearray,) # noqa: F821 # Find the base library and declare prototypes. def _guess_lib_name(): if sys.platform == 'darwin': return ('libchromaprint.1.dylib', 'libchromaprint.0.dylib') elif sys.platform == 'win32': return ('chromaprint.dll', 'libchromaprint.dll') elif sys.platform == 'cygwin': return ('libchromaprint.dll.a', 'cygchromaprint-1.dll', 'cygchromaprint-0.dll') return ('libchromaprint.so.1', 'libchromaprint.so.0') for name in _guess_lib_name(): try: _libchromaprint = ctypes.cdll.LoadLibrary(name) break except OSError: pass else: raise ImportError("couldn't find libchromaprint") _libchromaprint.chromaprint_get_version.argtypes = () _libchromaprint.chromaprint_get_version.restype = ctypes.c_char_p _libchromaprint.chromaprint_new.argtypes = (ctypes.c_int,) _libchromaprint.chromaprint_new.restype = ctypes.c_void_p _libchromaprint.chromaprint_free.argtypes = (ctypes.c_void_p,) _libchromaprint.chromaprint_free.restype = None _libchromaprint.chromaprint_start.argtypes = \ (ctypes.c_void_p, ctypes.c_int, ctypes.c_int) _libchromaprint.chromaprint_start.restype = ctypes.c_int _libchromaprint.chromaprint_feed.argtypes = \ (ctypes.c_void_p, ctypes.POINTER(ctypes.c_char), ctypes.c_int) _libchromaprint.chromaprint_feed.restype = ctypes.c_int _libchromaprint.chromaprint_finish.argtypes = (ctypes.c_void_p,) _libchromaprint.chromaprint_finish.restype = ctypes.c_int _libchromaprint.chromaprint_get_fingerprint.argtypes = \ (ctypes.c_void_p, ctypes.POINTER(ctypes.c_char_p)) _libchromaprint.chromaprint_get_fingerprint.restype = ctypes.c_int _libchromaprint.chromaprint_decode_fingerprint.argtypes = \ (ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_int32)), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.c_int) _libchromaprint.chromaprint_decode_fingerprint.restype = ctypes.c_int _libchromaprint.chromaprint_encode_fingerprint.argtypes = \ (ctypes.POINTER(ctypes.c_int32), ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_int), ctypes.c_int) _libchromaprint.chromaprint_encode_fingerprint.restype = ctypes.c_int _libchromaprint.chromaprint_dealloc.argtypes = (ctypes.c_void_p,) _libchromaprint.chromaprint_dealloc.restype = None # Main interface. class FingerprintError(Exception): """Raised when a call to the underlying library fails.""" def _check(res): """Check the result of a library call, raising an error if the call failed. """ if res != 1: raise FingerprintError() class Fingerprinter(object): ALGORITHM_TEST1 = 0 ALGORITHM_TEST2 = 1 ALGORITHM_TEST3 = 2 ALGORITHM_DEFAULT = ALGORITHM_TEST2 def __init__(self, algorithm=ALGORITHM_DEFAULT): self._ctx = _libchromaprint.chromaprint_new(algorithm) def __del__(self): _libchromaprint.chromaprint_free(self._ctx) del self._ctx def start(self, sample_rate, num_channels): """Initialize the fingerprinter with the given audio parameters. """ _check(_libchromaprint.chromaprint_start( self._ctx, sample_rate, num_channels )) def feed(self, data): """Send raw PCM audio data to the fingerprinter. Data may be either a bytestring or a buffer object. """ if isinstance(data, BUFFER_TYPES): data = str(data) elif not isinstance(data, bytes): raise TypeError('data must be bytes, buffer, or memoryview') _check(_libchromaprint.chromaprint_feed( self._ctx, data, len(data) // 2 )) def finish(self): """Finish the fingerprint generation process and retrieve the resulting fignerprint as a bytestring. """ _check(_libchromaprint.chromaprint_finish(self._ctx)) fingerprint_ptr = ctypes.c_char_p() _check(_libchromaprint.chromaprint_get_fingerprint( self._ctx, ctypes.byref(fingerprint_ptr) )) fingerprint = fingerprint_ptr.value _libchromaprint.chromaprint_dealloc(fingerprint_ptr) return fingerprint def decode_fingerprint(data, base64=True): result_ptr = ctypes.POINTER(ctypes.c_int32)() result_size = ctypes.c_int() algorithm = ctypes.c_int() _check(_libchromaprint.chromaprint_decode_fingerprint( data, len(data), ctypes.byref(result_ptr), ctypes.byref(result_size), ctypes.byref(algorithm), 1 if base64 else 0 )) result = result_ptr[:result_size.value] _libchromaprint.chromaprint_dealloc(result_ptr) return result, algorithm.value def encode_fingerprint(fingerprint, algorithm, base64=True): fp_array = (ctypes.c_int * len(fingerprint))() for i in range(len(fingerprint)): fp_array[i] = fingerprint[i] result_ptr = ctypes.POINTER(ctypes.c_char)() result_size = ctypes.c_int() _check(_libchromaprint.chromaprint_encode_fingerprint( fp_array, len(fingerprint), algorithm, ctypes.byref(result_ptr), ctypes.byref(result_size), 1 if base64 else 0 )) result = result_ptr[:result_size.value] _libchromaprint.chromaprint_dealloc(result_ptr) return result RE: Fingerprint audio - chromaprint and get fingerprint - alessandro87gatto - Apr-15-2019 Hi, I'm continuing to build the code. The code I posted earlier compares the fingerprints of the tracks in two directories. Now I would like to compare an audio that I acquire from a microphone, with the files present in a folder. I acquire the audio with the code: # Importazione Librerie import pyaudio import wave # Definizione del segnale sonoro form_1 = pyaudio.paInt16 # risoluzione segnale sonoro in bit (16 bit) chans = 1 # 1 canale samp_rate = 44100 # 44.1kHz frequenza di campionamento chunk = 4096 # 2^12 campioni analisi record_secs = 200 # durata registrazione in secondi dev_index = 2 # indice del dispositivo wav_output_filename = 'test.wav' # nome del file con estensione “.wav” file = open("test.txt", "wb") # creazione del file # Creazione istanza pyaudio audio = pyaudio.PyAudio() # Creazione stream pyaudio stream = audio.open(format=form_1, rate=samp_rate, channels=chans, \ input_device_index=dev_index, input=True, \ frames_per_buffer=chunk) # rate=frequenza campionamento # channels=numero di canali # input_device_index=indice del dispositivo di input da utilizzare # input=specifica se si tratta di un flusso di input # frames_per_buffer=specifica il numero di fotogrammi # Se siamo arrivati qui vuol dire che è iniziata la registrazione print("recording") frames = [] # ciclo sul flusso e aggiunti i blocchi audio all’array # range() genera una lista di numeri, che viene generalmente utilizzata per iterae con cicli for. for ii in range(0, int((samp_rate / chunk) * (record_secs / 10))): data = stream.read(chunk) frames.append(data) print(len(frames)) file.write(data) # scrivo dentro il file print("finished recording") # stop the stream, close it, and terminate the pyaudio instantiation stream.stop_stream() stream.close() audio.terminate() # save the audio frame sas .wav file wavefile = wave.open(wav_output_filename, 'wb') # crea file se non esiste, altrimenti lo modifica wavefile.setnchannels(chans) wavefile.setsampwidth(audio.get_sample_size(form_1)) wavefile.setframerate(samp_rate) wavefile.writeframes(b''.join(frames)) wavefile.close() file.close() # chiusura del fileAt the moment the audio acquired for "recorder_sec" saves it on file ".wav". Comparing this ".wav" with those in the directory works but doesn't make sense, as I would lose the advantage of the live. How could I change the code? Thank you RE: Fingerprint audio - chromaprint and get fingerprint - nilamo - Apr-15-2019 You're currently using acoustid.fingerprint_file(filepath) to get a fingerprint. If you instead use acoustid.fingerprint(samplerate, channels, pcmiter, maxlength=MAX_AUDIO_LENGTH) , you can feed raw pcm data into it to get a fingerprint of a stream. https://github.com/beetbox/pyacoustid/blob/master/acoustid.py#L194I don't know if it'll be fast enough to be "live", there will probably be a slight delay (though it might only be a second or less of a delay). RE: Fingerprint audio - chromaprint and get fingerprint - alessandro87gatto - Apr-17-2019 Thank you for your answer. But do you implement it in the code? My user code allows you to record audio from a USB microphone by saving the track in .wav and compare story track with all the tracks in another directory. ''' Recupero e Confronto delle Fingerprint con relativo calcolo di Similarità Confronto delle tracce audio presenti nella directory "partial" con quelle presenti nella directory "full" Package da installare: Preinstallati in PyCharm di default durante creazione progetto: • pip • setuptools • PyAudio Mediante installatore dei package: • pyacoustid • chromaprint • numpy • matplotlib • fuzzywuzzy • pyfingerprint • python-Levenshtein Si installano autonomamente durante l'installazione dei precedenti • Pillow • audioread • certifi • chardet • cycler • idna • kiwisolver • pyparsing • pyserial • python-dateutil • requestes • six • urllib3 ''' # Importazione Librerie import acoustid import sys import os import chromaprint import numpy as np import matplotlib.pyplot as plt from fuzzywuzzy import fuzz # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # ''' Registrazione audio mediante microfono usb con salvataggio su file ".wav" Package da installare: Preinstallati in PyCharm di default durante creazione progetto: • pip • setuptools Mediante installatore dei package: • PyAudio ''' # Importazione Librerie import pyaudio import wave # Definizione del segnale sonoro form_1 = pyaudio.paInt16 # risoluzione segnale sonoro in bit (16 bit) chans = 1 # 1 canale samp_rate = 44100 # 44.1kHz frequenza di campionamento chunk = 4096 # 2^12 campioni analisi record_secs = 50 # durata registrazione in secondi dev_index = 2 # indice del dispositivo wav_output_filename = '/Users/alessandrorosina/Desktop/rescue_recognition/stream/stream_fingerprint.wav' # nome del file con estensione “.wav” # Creazione istanza pyaudio audio = pyaudio.PyAudio() # Creazione stream pyaudio stream = audio.open(format=form_1, rate=samp_rate, channels=chans, \ input_device_index=dev_index, input=True, \ frames_per_buffer=chunk) # rate = frequenza campionamento # channels = numero di canali # input_device_index = indice del dispositivo di input da utilizzare # input = specifica se si tratta di un flusso di input # frames_per_buffer = specifica il numero di fotogrammi # Se siamo arrivati qui vuol dire che è iniziata la registrazione print("recording") frames = [] # ciclo sul flusso e aggiunti i blocchi audio all’array # range() genera una lista di numeri, che viene generalmente utilizzata per iterae con cicli for. for ii in range(0, int((samp_rate / chunk) * (record_secs / 10))): data = stream.read(chunk) frames.append(data) DIR_DATABASE = '/Users/alessandrorosina/Desktop/rescue_recognition/track' DIR_SAMPLES = '/Users/alessandrorosina/Desktop/rescue_recognition/stream' def get_fingerprint(filepath): """ Get fingerprint (list of signed integer), version, duration """ duration, fp_encoded = acoustid.fingerprint_file(filepath) fp, version = chromaprint.decode_fingerprint(fp_encoded) # acoustid.fingerprint(samplerate, channels, pcmiter, maxlength=MAX_AUDIO_LENGTH) return fp, version, duration def build_fingerprint_database(dirpath, file_ext='.wav'): """ Build database from directory of audio files """ database = {} print('\nProcessing {}..'.format(dirpath)) for f in os.listdir(dirpath): path = os.path.join(dirpath, f) name, ext = os.path.splitext(f) if os.path.isfile(path) and ext == file_ext: print('Getting fingerprint from database item: {}..'.format(f)) database[f], version, duration = get_fingerprint(path) return database ''' def build_fingerprint_stream(data_stream): """ Build database from directory of audio files """ database1 = {} print('\nProcessing stream {}..'.format(data_stream)) database1[f], version, duration = get_fingerprint(data_stream) return database1 ''' def plot_fingerprints(db): """ Visualize fingerprints in database """ fig = plt.figure() numrows = len(db) plot_id = 1 for name, fp in db.items(): # single column grid a = fig.add_subplot(numrows, 1, plot_id) imgplot = plt.imshow(get_fingerprint_bitmap(fp)) a.set_title(name) plot_id += 1 plt.show() def get_fingerprint_bitmap(fp): """ Plot list of uint32 as (32, len(list)) bitmap """ bitmap = np.transpose(np.array([[b == '1' for b in list('{:32b}'.format(i & 0xffffffff))] for i in fp])) return bitmap stream.stop_stream() # stop dello stream stream.close() # chiusura del canale di acquisizione audio.terminate() # fine traccia audio generata # Salvataggio dello stream su file ".wav" wavefile = wave.open(wav_output_filename, 'wb') # crea file se non esiste, altrimenti lo modifica wavefile.setnchannels(chans) wavefile.setsampwidth(audio.get_sample_size(form_1)) wavefile.setframerate(samp_rate) wavefile.writeframes(b''.join(frames)) wavefile.close() if __name__ == '__main__': # Caricamento directory stream e track database = build_fingerprint_database(DIR_DATABASE) samples = build_fingerprint_database(DIR_SAMPLES) print("inoltro path alla funzione build_fingerprint_database") print('\n') # Ricerca di ogni corrispondenza migliore for sample, sample_fp in samples.items(): print('Similarity score of "{}":'.format(sample)) best_match = None for name, fp in database.items(): similarity = fuzz.ratio(sample_fp, fp) if not best_match or best_match['score'] < similarity: best_match = { 'score': similarity, 'name': name } print('{} {}%'.format(name, similarity)) print('Best match: {name} ({score}%)\n'.format(**best_match)) # plot database plot_fingerprints(database) # Fingerprint delle canzoni full #plot_fingerprints(samples) # Fingerprint delle canzoni campione |