音频信号处理
In [1]:
import librosa
import librosa.display
import numpy as np
import matplotlib.pyplot as plt
In [2]:
def read_wav_info(filepath):
# sr=None 表示保持原始采样率,不重采样
y, sr = librosa.load(filepath, sr=None, mono=False)
# y为返回读取的音频时间序列
# y.shape:单声道为 (n_samples,),多声道为 (n_channels, n_samples)
if y.ndim == 1:
n_channels = 1
n_samples = y.shape[0]
else:
n_channels = y.shape[0]
n_samples = y.shape[1]
duration = n_samples / sr
print(f"采样率 : {sr} Hz")
print(f"时长 : {duration:.3f} 秒")
print(f"声道数 : {n_channels}")
print(y.ndim)
读取音频信号的相关信息¶
y,sr=librosa.load(filepath, sr=None, mono=False) 采样率为sr;如果$y.ndim$为1说明是单声道,时间为$\frac{y.shape[0]}{sr}$,如果$ndim$为2说明为多声道,且声道数为$y.shape[0]$,音频时长为$\frac{y.shape[1]}{sr}$
In [3]:
if __name__ == "__main__":
read_wav_info("example.wav")
采样率 : 48000 Hz 时长 : 4.130 秒 声道数 : 2 2
时域波形图¶
In [4]:
y,sr = librosa.load("example.wav", sr=None, mono=True)
# 采样率不变,将双通道转化为单通道
print(f"采样率: {sr} Hz, 时长: {len(y)/sr:.2f} 秒")
fig,ax=plt.subplots(figsize=(10, 3))
librosa.display.waveshow(y, sr=sr,ax=ax,color="steelblue")
ax.set_xlabel("Time")
ax.set_ylabel("Amplitude")
ax.set_title("Waveform")
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
采样率: 48000 Hz, 时长: 4.13 秒
功率谱(线性与转化为dB后的对比)¶
In [5]:
y,sr = librosa.load("example.wav", sr=None, mono=True)
# 采样率不变,将双通道转化为单通道
print(f"采样率: {sr} Hz, 时长: {len(y)/sr:.2f} 秒")
S=np.abs(librosa.stft(y))#S为信号的幅度
D = librosa.power_to_db(S**2, ref=np.max)
#ref=np.max相对于峰值功率算db
print("波形峰值:", np.max(np.abs(y)))
print("波形 RMS:", np.sqrt(np.mean(y**2)))
print("线性功率最大值:", (S**2).max())
print("dB 范围:", D.min(), D.max())
fig,ax=plt.subplots(2,1)
# ax[0].set_ylabel("log")
ax[0].set_title("Power spectrogram")
img1=librosa.display.specshow(S**2, sr=sr,ax=ax[0],x_axis='time',y_axis='log', cmap="magma")
img2=librosa.display.specshow(D, sr=sr,ax=ax[1],x_axis='time',y_axis='log', cmap="magma")
ax[1].set_xlabel("Time")
ax[1].set_title("Log—Power spectrogram")
plt.colorbar(img1,ax=ax[0])
plt.colorbar(img2,ax=ax[1], format="%+2.0f dB")
plt.tight_layout()
plt.show()
采样率: 48000 Hz, 时长: 4.13 秒 波形峰值: 0.022369385 波形 RMS: 0.003855737 线性功率最大值: 42.509605 dB 范围: -80.0 0.0
线性频谱和对数频谱的对比¶
In [6]:
y,sr = librosa.load("example.wav", sr=None, mono=True)
# 采样率不变,将双通道转化为单通道
print(f"采样率: {sr} Hz, 时长: {len(y)/sr:.2f} 秒")
S=np.abs(librosa.stft(y))#S为信号的幅度
D = librosa.amplitude_to_db(S, ref=np.max)
#ref=np.max相对于峰值算db
fig,ax=plt.subplots(2,1)
ax[0].set_title("Linear spectrogram")
img1=librosa.display.specshow(D, sr=sr,ax=ax[0],x_axis='time',y_axis='linear', cmap="magma")
img2=librosa.display.specshow(D, sr=sr,ax=ax[1],x_axis='time',y_axis='log', cmap="magma")
ax[1].set_xlabel("Time")
ax[1].set_title("Log spectrogram")
plt.colorbar(img1,ax=ax[0], format="%+2.0f dB")
plt.colorbar(img2,ax=ax[1], format="%+2.0f dB")
plt.tight_layout()
plt.show()
采样率: 48000 Hz, 时长: 4.13 秒
In [7]:
'''
librosa.feature.melspectrogram(
y=None, # 默认 None → 必须提供 y 或 S 之一
sr=22050, # 默认采样率 22050 Hz
S=None, # 默认 None → 没有预计算频谱
n_fft=2048, # 默认 FFT 窗口长度 2048
hop_length=512, # 默认帧移 512
win_length=None, # 默认 None → 自动取 win_length = n_fft
window='hann', # 默认汉宁窗
center=True, # 默认 True → 信号两端补 pad
pad_mode='reflect',# 默认反射填充
power=2.0, # 默认 2.0 → 输出功率谱
)
Cell In[7], line 1 ''' ^ _IncompleteInputError: incomplete input
Mel图¶
In [ ]:
y,sr = librosa.load("example.wav", sr=None, mono=True)
# 采样率不变,将双通道转化为单通道
print(f"采样率: {sr} Hz, 时长: {len(y)/sr:.2f} 秒")
S=np.abs(librosa.stft(y))#S为信号的幅度
M=librosa.feature.melspectrogram(S=S,sr=sr,power=1.0)
D = librosa.amplitude_to_db(M, ref=np.max)
#ref=np.max相对于峰值算db
fig,ax=plt.subplots()
ax.set_title("Mel spectrogram")
img1=librosa.display.specshow(D, sr=sr,ax=ax,x_axis='time',y_axis='mel', cmap="magma")
plt.colorbar(img1,ax=ax, format="%+2.0f dB")
plt.tight_layout()
plt.show()
Mel图的原理¶
In [ ]:
melfb = librosa.filters.mel(sr=22050,n_fft= 2048)
# array([[ 0. , 0.016, ..., 0. , 0. ],
# [ 0. , 0. , ..., 0. , 0. ],
# ...,
# [ 0. , 0. , ..., 0. , 0. ],
# [ 0. , 0. , ..., 0. , 0. ]])
import matplotlib.pyplot as plt
plt.figure()
librosa.display.specshow(melfb, x_axis='linear')
plt.ylabel('Mel filter')
plt.title('Mel filter bank')
plt.colorbar()
plt.tight_layout()
plt.show()
In [ ]:
import librosa
import numpy as np
import soundfile as sf
from IPython.display import Audio, display
def add_noise_snr(clean, snr_db):
noise = np.random.randn(len(clean)).astype(np.float32)
p_clean = np.mean(clean ** 2)
p_noise = np.mean(noise ** 2)
target_p_noise = p_clean / (10 ** (snr_db / 10))
noise = noise * np.sqrt(target_p_noise / p_noise)
noisy = clean + noise
max_val = np.max(np.abs(noisy))
if max_val > 1.0:
noisy = noisy / max_val * 0.99
return noisy
In [ ]:
clean, sr = librosa.load("example.wav", sr=None, mono=True)
display(Audio(clean, rate=sr)) # 原声
for snr in [0, 5, 10]:
noisy = add_noise_snr(clean, snr)
print(f"SNR = {snr} dB")
display(Audio(noisy, rate=sr))
sf.write(f"noisy_{snr}dB.wav", noisy, sr)
In [ ]: