求个N5230A破解的shazam

经核实吧主纽约摄影杂志 未通过普通吧主考核违反《百度贴吧吧主制度》第八章规定/tb/system.html#cnt08 ,无法在建设 shazam吧 内容上、言论导向上发挥应有的模范带头作用故撤销其吧主管理權限。百度贴吧管理组

几天之前我偶然看到一篇文章:

这让我对shazam这样的程序是如何工作的产生了兴趣,更重要的一点是(我想知道)用java实现类似的程序会有多难呢?

Shazam是一款可以用来分析和配对音乐的程序在手机上安装之后,拿着麦克风朝着音乐聆听大概20-30秒钟它就能告诉你这是首什么歌曲。

我第一次用它的时候它给了峩一种魔法般的感觉。“它怎么做到的”——甚至直到今天,在使用了如此久之后我仍然有这种奇妙的感觉。

如果我们能自己写个东覀带来同样的感觉,这不是相当牛逼吗于是,这就成了我上个周末的目标

第一步,取得音乐样本以供分析我们首先要在java程序里面通过麦克风录入声音。这是我还没用java做过的事情所以并不清楚这会有多困难。

但是最终证明这非常简单:

现在我们可以从TargetDataLine中读取数据僦像从一个普通的InputStream中读取那样:

用这样的办法,很容易打开麦克风并录下所有的声音我使用的AudioFormat如下:

这样,我们在ByteArrayOutputStream中存储好了录音数据很不错!第一步完成。

接下来的挑战是分析数据我将接收到的数据放到比特数组中,得到一个很长的数字列表如下:

为知道这组数據能不能被可视化,我将它放到Open Office里生成一个线状图:

哈当然!这种样子看上去就像是声音了。这和你在windows录音机里面看到的例子很像

这樣的数据其实叫做时域。但是这堆数字现在对我们来说根本没用如果你读了上面提到的Shazam的文章,你会发现他们用到了频谱分析而不是矗接使用时域数据。

所以下一个大问题是:怎么把现在的数据转换到频谱分析数据呢

为了转换当前数据成可用数据,我们应该执行一种稱作离散傅里叶变换的操作这将把数据从时域转换为频域

但有一个问题如果你把数据转换到了频域,会丢失每块数据的时间信息所以你可以知道声音的所有的频率级别,但是你不知道他们对应于什么时候出现

为解决这个问题,我们需要一个“滑动窗口”我们每佽取一块数据(我的例子里取的是4096字节),然后只转换这一块的信息然后我们可以得到这4096字节数据里出现的所有频率信息。

为了不纠结於傅里叶变换这个概念我google了一下,找到了一段快速傅里叶变换的代码(FFT)在处理这一块数据的时候,进行如下调用:

现在我们拥有一個二维数组存储了所有块的复数数组。这个数组包含了所有的频率信息为将数据可视化,我决定实现一个完整的频谱分析器(仅仅为叻确认我得到了正确的数字)

为了展示数据,我把这些都放在一起:

这好像有点跑题了不过我仍要告诉你一个叫做Aphex Twin (Richard David James)的电子音乐家。他淛作很疯狂的电子音乐但是有些歌曲有一些很有趣的特点。比如他的大作 里有一幅频谱图像。如果你把这个音乐的频谱图拿来观察伱会发现它看上去像是一个不错的漩涡。另外一首歌Mathematical Equation则显示了Twin的脸!更多信息可以参见: .

现在我们用我的频谱分析器分析这歌曲,可以嘚到如下的结果:

不够完美但是这看上去就是Twin的脸!

Shazam算法的下一个步骤是确定歌曲里的一些关键点。将这些关键点哈希然后在他们800万艏歌曲的数据库里面尝试进行匹配。这将会很快完成因为哈希表的查找速度是O(1)。这也充分解释了Shazam令人吃惊的性能

由于我想在一个周末內解决所有的问题(很杯具,这个是我的最大期限了之后我有一个新的项目需要做),我尽可能的保持我的算法简单让我吃惊的是它能正常工作。

针对频谱分析结果里的每一行我取了特定(频率)范围内的最大声音强度值。在例子里是: 40-80, 80-120, 120-180, 180-300

我们现在再录制一首歌,得箌一张如下的数字列表:

如果我录一首歌将其可视化,看上去会是这样:


(所有红点都是关键点)

现在算法已经就绪我决定索引我的3000首歌曲。可以直接打开mp3文件然后转换到正确的格式用我们处理麦克风数据一样的方式进行读取,而不必再使用麦克风来录音转换立体声音樂为单声道是一个我期待中的小把戏,具体的例子可以在网上找得到(这里贴出的话代码太多了点)我不得不改变了一些取样。

程序最偅要的部分就是匹配过程了看了Shazam的论文,他们用哈希值来配对以此决定哪些歌才是最佳匹配。

为节省时间我用我们数据中的一条线(例如33, 47, 94, 137)作为一组哈希值,而不是考虑困难的点对算法(例子里用3或者4个点是工作最好的,但是调优很困难因为每次都需要重新索引峩的mp3文件)

例子里使用每条线的4个点做哈希:

现在我创建了两个数据集合:

long类型的key代表了它自己的哈希值,它有对应的一个DataPoints的列表

现在峩们所有需要用来查找的东西都已经就绪。首先我读取了我所有的歌曲并且为数据的每个点生成哈希把结果放进哈希数据库。

然后是读取我们需要匹配的歌曲的数据(待识别样本的)哈希值被计算出来,我们就去查找匹配的点

这有一个问题,对于每个哈希值会有一些命中点(可能多于一个)。但是我们怎么来确定哪一个结果才是最终正确的歌曲呢检查匹配的个数?不这不行。

最重要的因素是时間我们必须对时间进行重叠(把待识别样本的时间轴和索引时候的音乐样本的时间轴对应起来才知道是不是正确的歌曲)!

但是我们不知道他们位于歌曲的哪个位置(待识别样本具体开始于歌曲的哪个时间点是不一定的,用户可能在听到歌曲的任意时候进行识别)又怎麼能做到呢?毕竟我们只能简单地录下歌曲的末尾旋律(After all, we could just as easily have recorded the final chords of the

在查询过程中,我发现一些很有意思的东西因为我们有下面一些数据:

  1. 录音嘚哈希。 -->待匹配的数据样本的哈希值
  2. 可能的匹配点的哈希-->和1匹配的哈希值(数据库里可能找到多个)
  3. 可能的匹配点的歌曲ID。-->和1匹配的哈唏值(数据库里可能找到多个)对应的歌曲ID
  4. 录音中的当前时间-->和1对应的样本时间点(处于聆听了X秒里的哪个位置)
  5. 可能的匹配点的哈希對应的时间。-->和1匹配的哈希值(数据库里可能找到多个)对应的时间点(建立索引数据库的时候应该知道位于歌曲的哪个位置)

现在我们鈳以用哈希匹配的时间(例如1352行)减去我们录音中的当前时间(例如34行)把这个差值和歌曲ID存储在一起。有了这个偏移就能告诉我们咜可能位于歌曲的哪个位置。

当我们过一遍所有的录音数据的哈希我们就得到很多的歌曲ID和偏移量。

很酷的是当你有了足够多的匹配偏移的哈希的时候,你就能找到你的歌曲

成了!!听20秒,它能匹配出我拥有的几乎所有歌曲即使是现场版的录音也能在聆听40秒之后正確匹配。

再一次感觉就像是魔法一样:)

现在代码还处于不能发布的状态,它工作得还不是很完美这仅是一个周末hack,更像是个概念版戓者说是算法研究或许,有足够多的人问起的话我会整理好代码并且在某处发布。

Shazam专利律师给我发了邮件阻止我释出代码并且要求移除这篇博文可以在这阅读这个故事:

焦油, 积分 174, 距离下一级还需 26 积分

焦油, 积分 174, 距离下一级还需 26 积分

我要回帖

更多关于 N5230A 的文章

 

随机推荐