This commit is contained in:
jeremygan2021
2026-03-02 22:43:04 +08:00
parent c0882a93a9
commit e0776a1839
18 changed files with 1331 additions and 82 deletions

View File

@@ -42,33 +42,70 @@ class AudioPlayer:
self.i2s = None
def play_tone(self, frequency, duration_ms, volume=0.5):
"""播放指定频率的音调"""
"""播放指定频率的音调 (优化内存版)"""
if self.i2s is None: return
sample_rate = self.config.get('sample_rate', 24000)
n_samples = int(sample_rate * duration_ms / 1000)
if frequency <= 0:
# 静音处理
time.sleep_ms(duration_ms)
return
# 振幅
amplitude = int(32767 * volume)
# STEREO: 每个采样 2 个声道 (L+R),每个声道 2 字节 (16-bit) -> 4 字节/帧
buffer = bytearray(n_samples * 4)
if frequency > 0:
period = sample_rate // frequency
half_period = period // 2
# 计算单周期采样数
period = sample_rate // frequency
# 目标 buffer 大小约 2048 字节 (防止 buffer 只有几字节导致 underrun)
target_size = 2048
frame_size = 4 # 16bit stereo
# 计算 buffer 中包含多少个完整周期
period_bytes = period * frame_size
repeats = max(1, target_size // period_bytes)
buffer_bytes = repeats * period_bytes
buffer = bytearray(buffer_bytes)
# 填充 buffer
half_period = period // 2
# 预计算采样值的高低字节
pos_val = amplitude
neg_val = -amplitude
pos_low = pos_val & 0xFF
pos_high = (pos_val >> 8) & 0xFF
neg_low = neg_val & 0xFF
neg_high = (neg_val >> 8) & 0xFF
for i in range(period * repeats):
# 方波:前半周期高电平,后半周期低电平
if (i % period) < half_period:
low, high = pos_low, pos_high
else:
low, high = neg_low, neg_high
for i in range(n_samples):
# 方波:前半周期高电平,后半周期低电平
sample = amplitude if (i % period) < half_period else -amplitude
# 左声道
struct.pack_into('<h', buffer, i * 4, sample)
# 右声道
struct.pack_into('<h', buffer, i * 4 + 2, sample)
else:
# 静音缓冲区默认为0
pass
idx = i * 4
buffer[idx] = low
buffer[idx+1] = high
buffer[idx+2] = low
buffer[idx+3] = high
# 计算总共需要写入的数据量
total_bytes = int((sample_rate * duration_ms / 1000) * frame_size)
written = 0
try:
# 写入多次以确保缓冲区填满并开始播放
self.i2s.write(buffer)
while written < total_bytes:
to_write = min(len(buffer), total_bytes - written)
if to_write == len(buffer):
self.i2s.write(buffer)
else:
self.i2s.write(buffer[:to_write])
written += to_write
except Exception as e:
print(f"Write error: {e}")