from machine import I2S, Pin import struct import time import math from config import CURRENT_CONFIG class AudioPlayer: def __init__(self): self.i2s = None self.config = None if hasattr(CURRENT_CONFIG, 'audio') and CURRENT_CONFIG.audio.get('enabled', False): self.config = CURRENT_CONFIG.audio self._init_audio() else: print("Audio not enabled in config") def _init_audio(self): """初始化音频输出""" # 从配置中获取引脚 bck = self.config.get('bck') ws = self.config.get('ws') sd = self.config.get('sd') sample_rate = self.config.get('sample_rate', 24000) print(f"Init Speaker: BCK={bck}, WS={ws}, SD={sd}") try: # MAX98357A 配置尝试: # 使用 I2S.STEREO 格式通常更稳定,MAX98357A 会自动混合 L+R self.i2s = I2S( 0, sck=Pin(bck), ws=Pin(ws), sd=Pin(sd), mode=I2S.TX, bits=16, format=I2S.STEREO, # 修改为 STEREO rate=sample_rate, ibuf=20000, ) except Exception as e: print(f"Speaker init failed: {e}") 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) 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 for i in range(n_samples): # 方波:前半周期高电平,后半周期低电平 sample = amplitude if (i % period) < half_period else -amplitude # 左声道 struct.pack_into('>> Playing Mario Theme...") # Note frequencies NOTE_E5 = 659 NOTE_C5 = 523 NOTE_G5 = 784 NOTE_G4 = 392 # (frequency, duration_ms) # 马里奥主题曲开头 melody = [ (NOTE_E5, 150), (NOTE_E5, 150), (0, 150), (NOTE_E5, 150), (0, 150), (NOTE_C5, 150), (NOTE_E5, 150), (0, 150), (NOTE_G5, 150), (0, 450), (NOTE_G4, 150), (0, 450) ] for freq, duration in melody: if freq == 0: time.sleep_ms(duration) else: self.play_tone(freq, duration, 0.3) # 短暂的停顿,避免音符粘连 time.sleep_ms(10) class Microphone: def __init__(self): self.i2s = None self.config = None if hasattr(CURRENT_CONFIG, 'mic') and CURRENT_CONFIG.mic.get('enabled', False): self.config = CURRENT_CONFIG.mic self._init_mic() else: print("Mic not enabled in config") def _init_mic(self): """初始化麦克风""" # 从配置中获取引脚 sck = self.config.get('sck') ws = self.config.get('ws') sd = self.config.get('sd') sample_rate = self.config.get('sample_rate', 16000) print(f"Init Mic: SCK={sck}, WS={ws}, SD={sd}") try: self.i2s = I2S( 1, sck=Pin(sck), ws=Pin(ws), sd=Pin(sd), mode=I2S.RX, bits=32, # ICS-43434 需要 32位 时钟周期 format=I2S.MONO, rate=sample_rate, ibuf=20000, ) except Exception as e: print(f"Mic init failed: {e}") self.i2s = None def readinto(self, buf): """读取数据到缓冲区""" if self.i2s: return self.i2s.readinto(buf) return 0