def distance(song1, song2): """ Wrapper around `bl_distance_file` function. Params: - filename1 is the first file to use. - filename2 is the second file to use. Returns a dict {distance, song1, song2} containing the computed distance and the created `bl_song` objects. """ if isinstance(song1, str) and isinstance(song2, str): filename1 = ffi.new("char[]", song1.encode("utf-8")) filename2 = ffi.new("char[]", song2.encode("utf-8")) song1 = ffi.new("struct bl_song *") song2 = ffi.new("struct bl_song *") return { "distance": lib.bl_distance_file(filename1, filename2, song1, song2), "song1": bl_song(c_struct=song1), "song2": bl_song(c_struct=song2) } elif isinstance(song1, bl_song) and isinstance(song2, bl_song): return { "distance": lib.bl_distance(song1["force_vector"], song2["force_vector"]), "song1": song1, "song2": song2 } else: return {"distance": None, "song1": None, "song2": None}
def cosine_similarity(song1, song2): """ Wrapper around `bl_cosine_similarity` function. Params: - filename1 is the first file to use. - filename2 is the second file to use. Returns a dict {similarity, song1, song2} containing the computed cosine similarity and the created `bl_song` objects. """ if isinstance(song1, str) and isinstance(song2, str): filename1 = ffi.new("char[]", song1.encode("utf-8")) filename2 = ffi.new("char[]", song2.encode("utf-8")) song1 = ffi.new("struct bl_song *") song2 = ffi.new("struct bl_song *") return { "similarity": lib.bl_cosine_similarity_file(filename1, filename2, song1, song2), "song1": bl_song(c_struct=song1), "song2": bl_song(c_struct=song2) } elif isinstance(song1, bl_song) and isinstance(song2, bl_song): return { "similarity": lib.bl_cosine_similarity(song1["force_vector"], song2["force_vector"]), "song1": song1, "song2": song2 } else: return { "similarity": None, "song1": None, "song2": None }
def set(self, key, value): """ Set a data member with a conversion from Python type as much as possible. Params: - key is the id of the data member to set. - value is the value to set. """ # Ease manipulation of char* data members, convert python str() if self._types[key] == ffi.typeof("char *") and value != ffi.NULL: if value != ffi.NULL: value = ffi.new("char[]", value.encode("utf-8")) # Keep the value in a dict in this object to keep it alive and safe # from the garbage collector. self._keepalive[key] = value # Same for force_vector_s fields elif self._types[key] == ffi.typeof("struct force_vector_s"): if value == ffi.NULL: return # Initialization from a valid initializer (tuple, list or dict) value = ffi.new("struct force_vector_s[]", [value]) self._keepalive[key] = value value = value[0] # Same for array of int fields elif self._types[key] == ffi.typeof("int8_t *"): if value != ffi.NULL: value = ffi.new("int8_t[]", value) # Keep the value in a dict in this object to keep it alive and safe # from the garbage collector. self._keepalive[key] = value else: # Nothing to do pass return setattr(self._c_struct, key, value)
def __init__(self, filename=None, initializer=None, c_struct=None): """ Initialize a new `bl_song` object. Params: - filename is a path to a file to load and analyze (optional). - initializer is an initializer to feed to `ffi.new` allocation call. Valid initializers are a list or tuple or dict of the field values. - c_struct is a preexisting `struct bl_song *` to use for initialization. """ # Initializing private data members if c_struct is not None: self._c_struct = c_struct else: self._c_struct = ffi.new("struct bl_song *", initializer) self._types = {i[0]: i[1].type for i in ffi.typeof("struct bl_song").fields} # _keepalive is useful to prevent garbage # collector from collecting dynamically allocated # data members self._keepalive = {} if filename is not None: self.analyze(filename)
def __init__(self, filename=None, initializer=None, c_struct=None): """ Initialize a new `bl_song` object. Params: - filename is a path to a file to load and analyze (optional). - initializer is an initializer to feed to `ffi.new` allocation call. Valid initializers are a list or tuple or dict of the field values. - c_struct is a preexisting `struct bl_song *` to use for initialization. """ # Initializing private data members if c_struct is not None: self._c_struct = c_struct else: self._c_struct = ffi.new("struct bl_song *", initializer) self._types = { i[0]: i[1].type for i in ffi.typeof("struct bl_song").fields } # _keepalive is useful to prevent garbage # collector from collecting dynamically allocated # data members self._keepalive = {} if filename is not None: self.analyze(filename)
def analyze(self, filename): """ Load and analyze an audio file, putting it in a `bl_song` object. Params: - filename is the path to the file to load and analyze. """ filename_char = ffi.new("char[]", filename.encode("utf-8")) lib.bl_analyze(filename_char, self._c_struct)
def decode(self, filename): """ Decode an audio file and load it into this `bl_song` object. Do not run any analysis on it. Params: - filename is the path to the file to load. """ filename_char = ffi.new("char[]", filename.encode("utf-8")) lib.bl_audio_decode(filename_char, self._c_struct)
def envelope_analysis(self): """ Run an envelope analysis on a previously loaded file. Returns a {tempo, attack} dict, which is a direct mapping of `struct envelope_result_s`. Also updates the object data members. """ result = ffi.new("struct envelope_result_s *") lib.bl_envelope_sort(self._c_struct, result) return {"tempo": (result.tempo1, result.tempo2, result.tempo3), "attack": result.attack}
def envelope_analysis(self): """ Run an envelope analysis on a previously loaded file. Returns a {tempo, attack} dict, which is a direct mapping of `struct envelope_result_s`. Also updates the object data members. """ result = ffi.new("struct envelope_result_s *") lib.bl_envelope_sort(self._c_struct, result) return {"tempo": (result.tempo), "attack": result.attack}
def distance(filename1, filename2): """ Wrapper around `bl_distance` function. Params: - filename1 is the first file to use. - filename2 is the second file to use. Returns a dict {distance, song1, song2} containing the computed distance and the created `bl_song` objects. """ song1 = ffi.new("struct bl_song *") song2 = ffi.new("struct bl_song *") filename1 = ffi.new("char[]", filename1.encode("utf-8")) filename2 = ffi.new("char[]", filename2.encode("utf-8")) return { "distance": lib.bl_distance_file(filename1, filename2, song1, song2), "song1": bl_song(c_struct=song1), "song2": bl_song(c_struct=song2) }
def cosine_similarity(filename1, filename2): """ Wrapper around `bl_cosine_similarity` function. Params: - filename1 is the first file to use. - filename2 is the second file to use. Returns a dict {similarity, song1, song2} containing the computed cosine similarity and the created `bl_song` objects. """ song1 = ffi.new("struct bl_song *") song2 = ffi.new("struct bl_song *") filename1 = ffi.new("char[]", filename1.encode("utf-8")) filename2 = ffi.new("char[]", filename2.encode("utf-8")) return { "similarity": lib.bl_cosine_similarity(filename1, filename2, song1, song2), "song1": bl_song(c_struct=song1), "song2": bl_song(c_struct=song2), }
def cosine_similarity(filename1, filename2): """ Wrapper around `bl_cosine_similarity` function. Params: - filename1 is the first file to use. - filename2 is the second file to use. Returns a dict {similarity, song1, song2} containing the computed cosine similarity and the created `bl_song` objects. """ song1 = ffi.new("struct bl_song *") song2 = ffi.new("struct bl_song *") filename1 = ffi.new("char[]", filename1.encode("utf-8")) filename2 = ffi.new("char[]", filename2.encode("utf-8")) return { "similarity": lib.bl_cosine_similarity(filename1, filename2, song1, song2), "song1": bl_song(c_struct=song1), "song2": bl_song(c_struct=song2) }