查看对音乐进行分类的源代码
←
对音乐进行分类
跳转到:
导航
、
搜索
因为以下原因,你没有权限编辑本页:
您刚才请求的操作只有这个用户组中的用户才能使用:
用户
您可以查看并复制此页面的源代码:
=准备数据= 这次,我们的任务是对一批音乐进行分类。 音乐的训练数据从[http://opihi.cs.uvic.ca/sound/genres.tar.gz 这里]可以下载到。这个数据里包含了blue,classical 等十个音乐类别,每个音乐类别有一百首样本。每个样本都是一首歌的前30秒。不过这个数据集是.au格式的,我们需要先转换成比较易于python处理的格式:wma。从[http://sourceforge.net/projects/sox/ 这里]下载sox的windows安装版本。安装完之后,我们在windows的cmd窗口里,可以采取写命令的方式利用sox批量转音乐文件的格式。 一个比较傻瓜的方式是 1.先把cmd命令移动到genres下的某个文件夹,例如jazz(使用"cd /."回c盘根目录,使用"e:"跳转到e盘,然后继续用cd前往要去的文件夹); 2.然后“mkdir converted”来新建一个converted文件夹; 3.接着使用如下命令批量装换jazz中的.au文件到converted文件夹中: <syntaxhighlight lang="python"> for %x in (*.au) do C:\sox-14-3-2\sox.exe %x E:\wulingfei\music_classification\genres\jazz\converted\%x.wav </syntaxhighlight> 在本练习中,我们只使用到jazz,classical,country, pop, rock, metal六个类型,所以只要在这六个文件夹下分别重复以上三个步骤就可以了。 =音频文件的频谱图= 我们可以先把一个wma文件读入python,然后绘制它的频谱图(spectrogram)来看看是什么样的。 <syntaxhighlight lang="python"> from scipy.io import wavfile from matplotlib.pyplot import specgram import matplotlib.pyplot as plt sample_rate, X = wavfile.read("E:\wulingfei\music_classification\genres\jazz\converted\jazz.00000.au.wav") print sample_rate, X.shape specgram(X, Fs=sample_rate, xextent=(0,30)) plt.xlabel("frequency") plt.ylabel("amplitude") </syntaxhighlight> [[File:music_classification_1.png|400px]] 上图就是一个jazz音乐样本的频谱图。当然,我们也可以把每一种的音乐都抽一些出来打印频谱图以便比较,如下图: [[File:music_classification_2.png|800px]] 从肉眼就可以看出一些区分,金属音乐的能量在各个频率上都比较强,爵士则是分布很不均匀的。 <syntaxhighlight lang="python"> figure(num=None, figsize=(18, 9), dpi=80, facecolor='w', edgecolor='k') plt.subplot(6,3,1);plotSpec("classical","00001");plt.subplot(6,3,2);plotSpec("classical","00002") plt.subplot(6,3,3);plotSpec("classical","00003");plt.subplot(6,3,4);plotSpec("jazz","00001") plt.subplot(6,3,5);plotSpec("jazz","00002");plt.subplot(6,3,6);plotSpec("jazz","00003") plt.subplot(6,3,7);plotSpec("country","00001");plt.subplot(6,3,8);plotSpec("country","00002") plt.subplot(6,3,9);plotSpec("country","00003");plt.subplot(6,3,10);plotSpec("pop","00001") plt.subplot(6,3,11);plotSpec("pop","00002");plt.subplot(6,3,12);plotSpec("pop","00003") plt.subplot(6,3,13);plotSpec("rock","00001");plt.subplot(6,3,14);plotSpec("rock","00002") plt.subplot(6,3,15);plotSpec("rock","00003");plt.subplot(6,3,16);plotSpec("metal","00001") plt.subplot(6,3,17);plotSpec("metal","00002");plt.subplot(6,3,18);plotSpec("metal","00003") plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0) </syntaxhighlight> =什么是快速(离散)傅里叶变换(FFT)?= FFT是一种数据处理技巧,它可以把time domain上的数据,例如一个音频,拆成一堆基准频率,然后投射到frequency domain上。 为了理解FFT,我们可以先生成三个音频文件。在cmd环境下输入 <syntaxhighlight lang="python"> C:\sox-14-3-2\sox.exe --null -r 22050 sine_a.wav synth 0.2 sine 400 C:\sox-14-3-2\sox.exe --null -r 22050 sine_b.wav synth 0.2 sine 3000 C:\sox-14-3-2\sox.exe --combine mix --volume 1 sine_b.wav --volume 0.5 sine_a.wav sine_mix.wav </syntaxhighlight> 生成三个音频文件。如果我们播放的话,会发现sine_a声音比较低,sine_b声音比较高,而sine_mix则混合了两者。 [[File:music_classification_3.png|600px]] <syntaxhighlight lang="python"> figure(num=None, figsize=(12, 8), dpi=80, facecolor='w', edgecolor='k') plt.subplot(3,2,1) sample_rate, a = wavfile.read("E:/wulingfei/music_classification/sine_a.wav") specgram(a, Fs=sample_rate, xextent=(0,30)) plt.xlabel("time") plt.ylabel("frequency") plt.title("400 HZ sine wave") plt.subplot(3,2,2) fft_a = abs(scipy.fft(a)) specgram(fft_a) plt.xlabel("frequency") plt.ylabel("amplitude") plt.title("FFT of 400 HZ sine wave") plt.subplot(3,2,3) sample_rate, b = wavfile.read("E:/wulingfei/music_classification/sine_b.wav") specgram(b, Fs=sample_rate, xextent=(0,30)) plt.xlabel("time") plt.ylabel("frequency") plt.title("3000 HZ sine wave") plt.subplot(3,2,4) fft_b = abs(scipy.fft(b)) specgram(fft_b) plt.xlabel("frequency") plt.ylabel("amplitude") plt.title("FFT of 3000 HZ sine wave") plt.subplot(3,2,5) sample_rate, c = wavfile.read("E:/wulingfei/music_classification/sine_mix.wav") specgram(c, Fs=sample_rate, xextent=(0,30)) plt.xlabel("time") plt.ylabel("frequency") plt.title("Mixed sine wave") plt.subplot(3,2,6) fft_c = abs(scipy.fft(c)) specgram(fft_c) plt.xlabel("frequency") plt.ylabel("amplitude") plt.title("FFT of mixed sine wave") plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0) </syntaxhighlight> 本文一开始的示例jazz数据经过FFT变形是这样的: [[File:music_classification_4.png|600px]] <syntaxhighlight lang="python"> figure(num=None, figsize=(9, 6), dpi=80, facecolor='w', edgecolor='k') sample_rate, X = wavfile.read("E:/wulingfei/music_classification/genres/jazz/converted/jazz.00000.au.wav") plt.subplot(2,1,1) specgram(X, Fs=sample_rate, xextent=(0,30)) plt.xlabel("time") plt.ylabel("frequency") plt.subplot(2,1,2) fft_X = abs(scipy.fft(X)) specgram(fft_X) plt.xlabel("frequency") plt.ylabel("amplitude") plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0) </syntaxhighlight> =使用频域强度特征来判别音乐= 转换完数据后,我们就可以使用频域的特征来判别音乐数据了。这里我们考虑最简单的分类器,例如KNN方法。 <syntaxhighlight lang="python"> #---------prepare train data-------------------- genre_list = ["classical", "jazz", "country", "pop", "rock", "metal"] def getdata(g,n): ad="E:/wulingfei/music_classification/genres/"+g+"/converted/"+g+"."+"0000"+str(n)+".au.wav" sample_rate, X = wavfile.read(ad) fft_X = list(abs(scipy.fft(X)[:1000])) f=fft_X+[genre_list.index(g)] return f data=[] for g in genre_list: for n in range(10): data.append(getdata(g,n)) data=array(data) #-----------prepare test data------------------- sample_rate, test = wavfile.read("E:/wulingfei/music_classification/genres/metal/converted/metal.00080.au.wav") testdata=abs(scipy.fft(test))[:1000] #---------classify----------------------- def distance(p0, p1): return np.sum( (p0-p1)**2) def nn_classify(training_set, training_labels, new_example): dists = np.array([distance(t, new_example) for t in training_set]) da=zip(dists,training_labels) da=array(sorted(da, key=lambda x:x[0])) votes = da[:3,1] return votes nn_classify(data[:,:-1], data[:,-1], testdata) </syntaxhighlight>
返回到
对音乐进行分类
。
个人工具
创建账户
登录
名字空间
页面
讨论
不转换
变换
不转换
简体
繁體
大陆简体
香港繁體
澳門繁體
大马简体
新加坡简体
台灣正體
查看
阅读
查看源代码
查看历史
操作
搜索
导航
集智百科
集智主页
最近更改
所有页面
帮助
工具箱
链入页面
相关更改
特殊页面