1986年出版的《音乐心理学》一书中说到“人类和音乐遵循共同的规律”。研究发现,人类大脑的生理信号具有带直线区域的线性规律,在生理上具有普遍性,产生公式:S(f) 1 / f ɑ。
二十世纪八十年代,有专家研究巴赫《第一勃兰登堡协奏曲》的音乐信号时发现,音乐信号的功率谱与人类大脑生理信号的功率谱相似,符合1/f信号公式。还发现, 音乐信号α越靠近数值1越好听 ,从科学上找到一个近似 参数 来判定音乐的悦耳度。2012年加拿大麦吉尔大学音乐系主任分析发现,音乐节奏也满足这个规律,α值为0.8。不同音乐体裁的α值不一样,所以也可以用这个数值反推音乐的风格体裁。不同作曲家风格音乐的α值不一样,但是作曲家们所作出来的各种风格体裁的音乐的 参数 是相似的。
现在的公司使用音乐分类,既可以向客户提供推荐,也可以仅仅作为产品。确定音乐类型是朝这个方向迈出的第一步。事实证明, 机器学习 技术在从大量 数据库 中提取趋势和模式方面非常成功。同样的原则也适用于音乐分析。
在本文中,我们将研究如何用Python处理音频/音乐信号,再利用所学的技能将音乐片段分类为不同的类型。
使用Python进行音频处理
声音以具有诸如频率、带宽、分贝等 参数 的音频信号的形式表示,典型的音频信号可以表示为幅度和时间的函数。
这些声音有多种格式,使计算机可以读取和分析它们。例如:
-
mp3格式
-
WMA(Windows Media Audio)格式
-
wav(波形音频文件)格式
音频库
Python有一些很棒的音频处理库,比如Librosa和PyAudio。还有一些内置的模块用于一些基本的音频功能。
我们将主要使用两个库进行音频采集和回放:
1. Librosa
它是一个Python模块,通常用于分析音频信号,但更倾向于音乐。它包括用于构建MIR(音乐 信息检索 )系统的nuts 和 bolts。示例和教程: https://librosa.github.io/librosa/
安装
pip install librosa conda install -c conda-forge librosa
为了提供更多的音频解码能力,您可以安装随许多音频解码器一起提供的ffmpeg。
2. IPython.display.Audio
IPython.display.Audio 让您直接在jupyter笔记本中播放音频。
加载音频文件
import librosa
audio_path = '../T08-violin.wav' x , sr = librosa.load(audio_path)
print(type(x), type(sr)) <class 'numpy.ndarray'> <class 'int'>
print(x.shape, sr) (396688,) 22050
这会将音频时间序列作为numpy数组返回,默认采样率(sr)为22KHZ mono。我们可以通过以下方式更改此行为:
librosa.load(audio_path, sr=44100)
以44.1KHz重新采样,或禁用重新采样。采样率是每秒传输的音频样本数,以Hz或kHz为单位。
librosa.load(audio_path, sr=None)
播放音频
使用IPython.display.Audio播放音频。
import IPython.display as ipd ipd.Audio(audio_path)
然后返回jupyter笔记本中的音频小部件,如下图所示,这个小部件在这里不起作用,但它可以在你的笔记本中使用,你甚至可以使用mp3或WMA格式作为音频示例。
可视化音频
波形
我们可以绘制音频数组librosa.display.waveplot:
%matplotlib inline import matplotlib.pyplot as plt import librosa.display
plt.figure(figsize=(14, 5)) librosa.display.waveplot(x, sr=sr)
这里,我们有波形幅度包络图。
谱图
谱图是通过视觉表示频谱的频率、声音或其他信号,因为它们随时间变化。频谱图有时被称为超声波仪,声纹或语音图。当数据在3D图中表示时,它们可以称为waterfalls。在二维阵列中,第一轴是频率,而第二轴是时间。
我们可以使用显示频谱图: librosa.display.specshow.
X = librosa.stft(x) Xdb = librosa.amplitude_to_db(abs(X)) plt.figure(figsize=(14, 5)) librosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='hz') plt.colorbar()
纵轴表示频率(从0到10kHz),横轴表示剪辑的时间。由于我们看到所有动作都发生在频谱的底部,我们可以将频率轴转换为对数轴。
librosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='log') plt.colorbar()
写音频
librosa.output.write_wav 将NumPy数组保存到WAV文件。
librosa.output.write_wav('example.wav', x, sr)
创建音频信号
现在让我们创建一个220Hz的音频信号,音频信号是一个numpy数组,所以我们将创建一个并将其传递给音频函数。
import numpy as np sr = 22050 # sample rate T = 5.0 # seconds t = np.linspace(0, T, int(T*sr), endpoint=False) # time variable x = 0.5*np.sin(2*np.pi*220*t)# pure sine wave at 220 Hz
Playing the audio ipd.Audio(x, rate=sr) # load a NumPy array
Saving the audio librosa.output.write_wav('tone_220.wav', x, sr)
特征提取
每个音频信号都包含许多特征。但是,我们必须提取与我们试图解决的问题相关的特征。提取要使用它们进行分析的特征的过程称为特征提取,让我们详细研究一些特征。
-
过零率
该特征在 语音识别 和音乐 信息检索 中都被大量使用。对于像金属和岩石那样的高冲击声,它通常具有更高的值。让我们计算示例音频片段的过零率。
# Load the signal x, sr = librosa.load('../T08-violin.wav')
#Plot the signal: plt.figure(figsize=(14, 5)) librosa.display.waveplot(x, sr=sr)
# Zooming in n0 = 9000 n1 = 9100 plt.figure(figsize=(14, 5)) plt.plot(x[n0:n1]) plt.grid()
似乎有6个过零点,让我们用librosa验证。
zero_crossings = librosa.zero_crossings(x[n0:n1], pad=False) print(sum(zero_crossings))
6
-
光谱质心
它指示声音的“质心”位于何处,并计算为声音中存在的频率的加权平均值。如果有两首歌曲,一首来自布鲁斯类型,另一首属于金属。与长度相同的布鲁斯流派歌曲相比,金属歌曲在最后有更多的频率。因此,布鲁斯歌曲的光谱质心将位于其光谱中间附近,而金属歌曲的光谱质心将朝向它的末端。
librosa.feature.spectral_centroid 计算信号中每帧的光谱质心:
spectral_centroids = librosa.feature.spectral_centroid(x, sr=sr)[0] spectral_centroids.shape (775,)
# Computing the time variable for visualization frames = range(len(spectral_centroids)) t = librosa.frames_to_time(frames)
# Normalising the spectral centroid for visualisation def normalize(x, axis=0): return sklearn.preprocessing.minmax_scale(x, axis=axis)
#Plotting the Spectral Centroid along the waveform librosa.display.waveplot(x, sr=sr, alpha=0.4) plt.plot(t, normalize(spectral_centroids), color='r')
到最后,光谱质心上升。
-
光谱衰减
它是信号形状的度量。librosa.feature.spectral_rolloff 计算信号中每帧的滚降系数:
spectral_rolloff = librosa.feature.spectral_rolloff(x+0.01, sr=sr)[0] librosa.display.waveplot(x, sr=sr, alpha=0.4) plt.plot(t, normalize(spectral_rolloff), color='r')
-
梅尔频率倒谱系数
信号的Mel频率倒谱系数(MFCC)是一小组特征(通常约10-20),其简明地描述了频谱包络的整体形状,它模拟了人声的特征。让我们这次用一个简单的循环波。
x, fs = librosa.load('../simple_loop.wav') librosa.display.waveplot(x, sr=sr)
librosa.feature.mfcc 通过音频信号计算MFCC:
mfccs = librosa.feature.mfcc(x, sr=fs) print mfccs.shape (20, 97)
#Displaying the MFCCs: librosa.display.specshow(mfccs, sr=sr, x_axis='time')
这里mfcc计算了超过97帧的20个MFCC。我们还可以执行特征缩放,使得每个系数维度具有零均值和单位方差:
import sklearn mfccs = sklearn.preprocessing.scale(mfccs, axis=1)