如何在Python中按指定采样率输出1-bit音频?
问题根源
你原有代码的采样率波动是因为裸for循环没有固定的时间控制,每次迭代的耗时受Python解释器调度、系统后台任务干扰,无法对齐固定的时间间隔。
方案1:用户态高精度定时锁定(实现最简单)
通过Python内置的perf_counter高精度计时器强制每次循环对齐1/采样率的时间间隔,支持直接使用源文件采样率或者固定48kHz:
from scipy.io import wavfile import time import RPi.GPIO as GPIO # 读取音频 samplerate, data = wavfile.read('rick.wav') # 如果需要强制固定48kHz,取消下行注释,先做重采样 # from scipy.signal import resample # target_samplerate = 48000 # data = resample(data, int(len(data) * target_samplerate / samplerate)) # samplerate = target_samplerate interval = 1 / samplerate left_channel = data[:, 0] GPIO.setmode(GPIO.BCM) piezoOutPin = 18 # 替换为你的实际引脚 GPIO.setup(piezoOutPin, GPIO.OUT) try: for d in left_channel: start = time.perf_counter() GPIO.output(piezoOutPin, d > 0) # 等待到本次间隔结束 while time.perf_counter() - start < interval: pass finally: GPIO.cleanup()
注意:该方案在低负载场景下精度足够,高负载下仍可能出现轻微抖动
方案2:内核态硬件定时输出(精度最高)
换用pigpio库替代默认的RPi.GPIO,pigpio直接调用内核级定时器,还支持预生成波形队列后台自动输出,完全不受用户态进程调度影响,精度可以做到微秒级:
from scipy.io import wavfile import pigpio import time # 读取音频 samplerate, data = wavfile.read('rick.wav') left_channel = data[:, 0] # 预处理生成1bit序列 bit_seq = [1 if d > 0 else 0 for d in left_channel] pi = pigpio.pi() piezoOutPin = 18 # 替换为你的实际引脚 pi.set_mode(piezoOutPin, pigpio.OUTPUT) # 生成波形脉冲 pulses = [] us_interval = int(1000000 / samplerate) # 转换为微秒间隔 for bit in bit_seq: if bit: pulses.append(pigpio.pulse(1<<piezoOutPin, 0, us_interval)) else: pulses.append(pigpio.pulse(0, 1<<piezoOutPin, us_interval)) # 发送波形 pi.wave_clear() pi.wave_add_generic(pulses) wave_id = pi.wave_create() pi.wave_send_once(wave_id) # 等待播放完成 while pi.wave_tx_busy(): time.sleep(0.1) # 清理 pi.wave_delete(wave_id) pi.stop()
如果要固定48kHz,和方案1一样先对音频做重采样再处理即可
补充优化项
- 运行脚本时给进程赋予实时优先级,Linux下可以用命令
sudo chrt -f 99 python3 your_script.py,进一步避免系统调度干扰 - 不要用
time.sleep()做间隔控制,大部分系统默认sleep精度只有10~15ms,远达不到48kHz要求的20.8μs间隔精度
内容的提问来源于stack exchange,提问作者10 Replies
相关产品推荐
相关产品推荐

