Python生成《小星星》音频存在背景杂音,求解决方法
解决Python生成《小星星》音频的背景杂音问题
你的代码产生杂音主要有三个原因,对应修改方案如下:
1. 静默音符错误使用低频正弦波
原代码里把静默音符设为1.0Hz的频率,这会生成极低频率的嗡嗡声。正确的做法是直接生成全零信号。
2. 音符切换时无过渡导致咔哒声
不同音符的波形在衔接处没有淡入淡出,波形突变会产生刺耳的咔哒杂音,需要给每个音符添加淡入淡出效果。
3. 频率舍入导致的波形不连续
原代码中对频率的舍入操作可能导致单个音符的波形周期不完整,衔接时出现微小突变,可通过调整波形生成逻辑避免不必要的舍入。
修改后的完整代码
import numpy as np from scipy.io.wavfile import write class Music: def __init__(self, notes, tempo, base_freq='C4'): self.notes = notes self.tempo = tempo self.base_freq = base_freq self.sample_rate = 44100 def generate_freq(self): octave = ['C', 'c', 'D', 'd', 'E', 'F', 'f', 'G', 'g', 'A', 'a', 'B'] num = int(self.base_freq[1]) delta = 4 - num bf = 261.63 * 2**delta note_freqs = {octave[i]: bf * pow(2, i/12) for i in range(len(octave))} note_freqs = {key: round(val, 2) for key, val in note_freqs.items()} note_freqs[''] = 0.0 # 静默音符设为0频率 return note_freqs def generate_wave(self, freq): time = 60 / self.tempo t = np.linspace(0, time, int(self.sample_rate * time), endpoint=False) if freq == 0.0: # 生成全零静默信号 wave = np.zeros_like(t) else: # 直接使用计算的频率,避免不必要的舍入 wave = np.sin(2 * np.pi * freq * t) # 添加淡入淡出效果,消除切换时的咔哒声 fade_samples = int(self.sample_rate * 0.01) # 10ms淡入淡出 if len(wave) > fade_samples * 2: wave[:fade_samples] *= np.linspace(0, 1, fade_samples) wave[-fade_samples:] *= np.linspace(1, 0, fade_samples) # 调整振幅到int16范围 wave *= 32767 return wave.astype(np.int16) def generate_digital_note(self): note_freqs = self.generate_freq() all_notes = [] for note in self.notes: freq = note_freqs[note] all_notes.append(self.generate_wave(freq)) return np.concatenate(all_notes) music_notes = 'C-C-G-G-A-A-G--F-F-E-E-D-D-C--G-G-F-F-E-E-D--G-G-F-F-E-E-D--C-C-G-G-A-A-G--F-F-E-E-D-D-C' music_notes = music_notes.split('-') twinkle_normal = Music(music_notes, 120) twinkle_normal_wave = twinkle_normal.generate_digital_note() write('twinkle-twinkle_clean.wav', 44100, twinkle_normal_wave)
修改说明
- 静默音符处理:将
note_freqs['']设为0.0,生成全零信号替代低频正弦波,彻底消除嗡嗡声。 - 淡入淡出效果:给每个音符前后添加10ms的线性淡入淡出,平滑波形衔接,去除咔哒杂音。
- 频率计算优化:移除了原代码中对频率的舍入调整,直接使用精确计算的频率值,减少波形不连续的可能。
- 类型提前转换:在生成波形时直接转为
np.int16,避免最后转换时的潜在精度问题。
内容的提问来源于stack exchange,提问作者prasadav
相关产品推荐
相关产品推荐

