我有一段时长大约为3.34 s 频率为1khz 的连续音频。该音频输入一个设备,经转换输出后,我想判断该音频是否还连续。 好了,这就是我的需求,看起来比较棘手,但我们稍稍了解音频采样率,码流,音频格式,通道的相关概念后,我们就可以用强大的python很快解决此问题。 关于音频的相关概念,请参考以下文章:
音频(一):时域图、 频谱图 Spectrum、 功率谱 https://blog.csdn.net/chumingqian/article/details/122947421 正弦形函数 https://baike.baidu.com/item/%E6%AD%A3%E5%BC%A6%E5%9E%8B%E5%87%BD%E6%95%B0/898409?fr=aladdin 音频处理库—librosa的安装与使用 https://blog.csdn.net/zzc15806/article/details/79603994/ Python绘制语音信号的波形图、频谱图和语谱图 https://zhuanlan.zhihu.com/p/371394137 ffmpeg基础流程:音频处理 https://blog.csdn.net/weixin_43907175/article/details/121595588 FFmpeg的音频处理详解 https://blog.csdn.net/fireroll/article/details/83032025
好了,基本概念已经确定,我接下来阐述我的判定音频是否连续的方法。 具体步骤就是求出音频的时域图,就是音频的强度相对于时间的图像。 由于我们的音频的频率是固定的,我们还可以求出频域图,很有趣的几张图像。 声波其实就是一种机械波,那么我们画出的时域图其实就是一种正弦波。 那么判断音频是否连续的方法就是对时域图积分,以标准音频的积分值为基准。若测试音频的时域图的积分值小于以上基准值,那么就是不连续的,即该声波的中间有空白出现。但是对标准音频的时域图积分的结果肯定是0,因为正弦图正负抵消,这就无法作为判定标准。 于是,我们可以取时域图的绝对值图像,求该绝对值图像的积分值,以此为基准值。 若测试音频的时域图的绝对值图像积分后小于该基准值,那么就可以判定该测试音频中间有断掉的。 我们提供的音频的格式如下: Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, s16p, 320 kb/s 采样率为44.1KHz,双声道,音频频率固定为1KHz。 以下为我画出的该音频的时域图,频域图,对数图。
求完绝对值后的时域图。 未求绝对值的原始时域图。
我的代码如下:
# - * - coding: utf-8 - * -
import librosa #Librosa是一个用于音频、音乐分析、处理的python工具包,一些常见的时频处理、特征提取、绘制声音图形等功能应有尽有,功能十分强大它是一个Python模块,通常用于分析音频信号,但更倾向于音乐。它包括用于构建MIR(音乐信息检索)系统的nuts 和 bolts
import librosa.display
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft
plt.figure(dpi=200) # 将显示的所有图分辨率调高
matplotlib.rc("font",family='SimHei') # 显示中文
matplotlib.rcParams['axes.unicode_minus']=False # 显示符号
def displayWaveform(): # 显示语音时域波形
"""
display waveform of a given speech sample
:param sample_name: speech sample name
:param fs: sample frequency
:return:
"""
samples, sr = librosa.load('reslut_audio.mp3', sr=44100) #sr 是采样率,单位是HZ,代表每秒对声音的采样数 samples 是总的样本数量,为时长(s)*采样率
#这会将音频时间序列作为numpy数组返回,默认采样率(sr)为22KHZ mono。我们可以通过以下方式更改此行为: librosa.load(audio_path, sr=44100)
#以44.1KHz重新采样,或禁用重新采样。采样率是每秒传输的音频样本数,以Hz或kHz为单位。librosa.load(audio_path, sr=None)
# samples = samples[6000:16000]
#samples=np.abs(samples)
print(f"总样本数量: {len(samples)}, 采样率(Hz):{sr}")
time = np.arange(0, len(samples)) * (1.0 / sr) # 求出各个时间点,即各个采样点所对应的时间点,采样率为44100,总样本数量是147294,音频时长3.34s,那么time列表就是在(0 , 3.34) 内有147294 个值,对应每个采样点所处的时间点
print(f"time 时间点数量: {len(time)}")
print(f"音频时长(s): {len(samples)/sr}")
print(f"打印samples: {samples}")
print(f"对时域波形图进行积分: {sum(samples)/sr}")
plt.plot(time, samples)
plt.title("语音信号时域波形")
plt.xlabel("时长(秒)")
plt.ylabel("振幅")
# plt.savefig("your dir\语音信号时域波形图", dpi=600)
plt.show()
def displaySpectrum(): # 显示语音频域谱线
samples, sr = librosa.load('reslut_audio.mp3', sr=16000)
print(len(samples))
# ft = librosa.stft(samples)
# magnitude = np.abs(ft) # 对fft的结果直接取模(取绝对值),得到幅度magnitude
# frequency = np.angle(ft) # (0, 16000, 121632)
ft = fft(samples)
print(len(ft), type(ft), np.max(ft), np.min(ft))
magnitude = np.absolute(ft) # 对fft的结果直接取模(取绝对值),得到幅度magnitude
#print(magnitude)
frequency = np.linspace(0, sr, len(magnitude)) # (0, 16000, 121632)
#print(frequency)
print(len(magnitude), type(magnitude), np.max(magnitude), np.min(magnitude))
print(len(frequency), type(frequency), np.max(frequency), np.min(frequency))
# plot spectrum,限定[:40000]
# plt.figure(figsize=(18, 8))
plt.plot(frequency[:40000], magnitude[:40000]) # magnitude spectrum
plt.title("语音信号频域谱线")
plt.xlabel("频率(赫兹)")
plt.ylabel("幅度")
plt.savefig("your dir语音信号频谱图", dpi=600)
plt.show()
# # plot spectrum,不限定 [对称]
# plt.figure(figsize=(18, 8))
# plt.plot(frequency, magnitude) # magnitude spectrum
# plt.title("语音信号频域谱线")
# plt.xlabel("频率(赫兹)")
# plt.ylabel("幅度")
# plt.show()
def displaySpectrogram():
samples, sr = librosa.load('reslut_audio.mp3', sr=16000)
# compute power spectrogram with stft(short-time fourier transform):
# 基于stft,计算power spectrogram
spectrogram = librosa.amplitude_to_db(librosa.stft(samples))
# show
librosa.display.specshow(spectrogram, y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('语音信号对数谱图')
plt.xlabel('时长(秒)')
plt.ylabel('频率(赫兹)')
plt.show()
if __name__ == '__main__':
displayWaveform()
displaySpectrum()
displaySpectrogram()
以下为打印结果: 总样本数量: 147294, 采样率(Hz):44100 time 时间点数量: 147294 音频时长(s): 3.34 打印samples: [0. 0. 0. … 0.80444336 0.8369751 0.60565186] 对时域波形图进行积分: 1.9839639683591535
检测音频是否连续的可以用displayWaveform()方法进行判断。 我们对该音频绝对值时域图积分后的值为: 对时域波形图进行积分: 1.9839639683591535
那么待检测音频的积分值若小于该值,1.9839639683591535,就说明该音频是不连续的
附录: 关于本案例定积分的推导步骤如下:
|