不能使用 SHA-256 等加密哈希值来比较两个音频文件之间的距离。加密哈希被刻意设计为不可预测的,并且理想情况下不会泄露有关已哈希输入的任何信息。
但是,有许多合适的acoustic fingerprinting 算法可以接受一段音频并返回一个指纹向量。然后,您可以通过查看两个音频片段对应的指纹向量的接近程度来衡量两个音频片段的相似度。
选择声学指纹算法
Chromaprint 是一种流行的开源声学指纹算法,在许多流行语言中都有bindings and reimplementations。 AcoustID 项目使用 Chromaprint,该项目正在构建一个开源数据库来收集流行音乐的指纹和元数据。
研究员 Joren Six 还编写并开源了声学指纹库 Panako 和 Olaf。但是,它们目前都以 AGPLv3 的形式获得许可,并且可能侵犯仍然有效的美国专利。
一些公司——例如Pex——销售用于检查任意音频文件是否包含受版权保护的材料的 API。如果您注册 Pex,他们会给您their closed-source SDK,用于根据他们的算法生成声学指纹。
生成和比较指纹
在这里,我假设您选择了 Chromaprint。您必须安装 libchromaprint 和 FFT 库。
我假设您选择了 Chromaprint,并且您想使用 Python 比较指纹,尽管一般原则适用于其他指纹库。
- 安装libchromaprint or the fpcalc command line tool。
- 从 PyPI 安装 pyacoustid Python 库。它将查找您现有的 libchromaprint 或 fpcalc 安装。
- 标准化您的音频文件以消除可能混淆 Chromaprint 的差异,例如音频文件开头的静音。还要记住,Chromaprin
- 虽然我通常使用measure the distance between vectors using NumPy,但许多 Chromaprint 用户通过计算指纹之间的
xor 函数并计算1 位的数量来比较两个音频文件。
这里有一些用于比较两个指纹之间距离的简单粗暴的 Python 代码。虽然如果我正在构建生产服务,我会在 C++ 或 Rust 中实现比较。
from operator import xor
from typing import List
# These imports should be in your Python module path
# after installing the `pyacoustid` package from PyPI.
import acoustid
import chromaprint
def get_fingerprint(filename: str) -> List[int]:
"""
Reads an audio file from the filesystem and returns a
fingerprint.
Args:
filename: The filename of an audio file on the local
filesystem to read.
Returns:
Returns a list of 32-bit integers. Two fingerprints can
be roughly compared by counting the number of
corresponding bits that are different from each other.
"""
_, encoded = acoustid.fingerprint_file(filename)
fingerprint, _ = chromaprint.decode_fingerprint(
encoded
)
return fingerprint
def fingerprint_distance(
f1: List[int],
f2: List[int],
fingerprint_len: int,
) -> float:
"""
Returns a normalized distance between two fingerprints.
Args:
f1: The first fingerprint.
f2: The second fingerprint.
fingerprint_len: Only compare the first `fingerprint_len`
integers in each fingerprint. This is useful
when comparing audio samples of a different length.
Returns:
Returns a number between 0.0 and 1.0 representing
the distance between two fingerprints. This value
represents distance as like a percentage.
"""
max_hamming_weight = 32 * fingerprint_len
hamming_weight = sum(
sum(
c == "1"
for c in bin(xor(f1[i], f2[i]))
)
for i in range(fingerprint_len)
)
return hamming_weight / max_hamming_weight
上面的函数可以让你比较两个指纹如下:
>>> f1 = get_fingerprint("1.mp3")
>>> f2 = get_fingerprint("2.mp3")
>>> f_len = min(len(f1), len(f2))
>>> fingerprint_distance(f1, f2, f_len)
0.35 # for example
您可以阅读有关如何使用 Chromaprint 计算不同音频文件之间距离的更多信息。 This mailing list thread 描述了如何比较 Chromaprint 指纹的理论。 This GitHub Gist 提供了另一种实现方式。