Files
mcp_screen/demo_audio_loopback.py
T

237 lines
9.4 KiB
Python

import time
import machine
from machine import Pin, I2S
import board_config
def play_ram_pcm(audio_chunks, channels=2, rate=16000, bits=16, volume=90):
from audio_util import ES8311
# 1. Start MCLK PWM using board config parameters
mclk_pwm = None
if board_config.audio_mclk_pin is not None:
mclk_pin = Pin(board_config.audio_mclk_pin, Pin.OUT)
mclk_pwm = machine.PWM(mclk_pin)
mclk_pwm.freq(board_config.audio_mclk_freq)
mclk_pwm.duty_u16(32768)
# 2. Wake up and configure ES8311 DAC
dac = ES8311(board_config.i2c_bus)
dac.init(sample_rate=rate)
dac.set_volume(volume)
# 3. Configure I2S TX
i2s_format = I2S.MONO if channels == 1 else I2S.STEREO
i2s = I2S(1,
sck=Pin(board_config.audio_i2s_sck),
ws=Pin(board_config.audio_i2s_ws),
sd=Pin(board_config.audio_i2s_tx_sd),
mode=I2S.TX,
ibuf=4096,
rate=rate,
bits=bits,
format=i2s_format)
# 4. Enable Speaker Amplifier
on_val = 0 if board_config.audio_amp_active_level == 0 else 1
off_val = 1 if board_config.audio_amp_active_level == 0 else 0
amp_pin = Pin(board_config.audio_amp_pin, Pin.OUT, value=on_val)
try:
print(f"Streaming raw audio to speaker from RAM ({len(audio_chunks)} chunks)...")
for chunk in audio_chunks:
i2s.write(chunk)
except Exception as e:
print("Error during RAM playback:", e)
finally:
time.sleep_ms(100) # Let buffer play out
amp_pin.value(off_val) # Disable amp
i2s.deinit()
if mclk_pwm:
mclk_pwm.deinit()
print("Playback complete.")
def main():
display = board_config.display_instance
print("=== Dynamic RAM-based Audio Loopback Script ===")
print(f"Board Detected: {board_config.BOARD_TYPE}")
# Initialize buttons using polling Pins instead of BoardButtons class
key_pin = Pin(18, Pin.IN, Pin.PULL_UP)
boot_pin = Pin(0, Pin.IN, Pin.PULL_UP)
# Helper to check if trigger is active
def is_talk_trigger_active():
if board_config.touch:
return board_config.touch.is_touched()
return key_pin.value() == 0
while True:
if display:
display.clear(0)
if board_config.BOARD_TYPE == 'WAVESHARE_RLCD':
display.text("RLCD Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 390, 20, 1)
display.text("1. Press KEY button to record 10s", 15, 60, 1)
display.text("2. Playback will start automatically", 15, 80, 1)
display.text("Ready (RAM-based)...", 15, 120, 1)
else:
display.text("Touch Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 310, 20, 1)
display.text("1. Press screen/KEY to record 10s", 10, 50, 1)
display.text("2. Playback starts automatically", 10, 70, 1)
display.text("Ready (RAM-based)...", 10, 100, 1)
display.show()
print("Ready: Press and hold key/screen to record...")
start_wait = time.ticks_ms()
while not is_talk_trigger_active():
if boot_pin.value() == 0 or time.ticks_diff(time.ticks_ms(), start_wait) > 120000:
print("Exit condition met. Deleting flag and resetting...")
if display:
display.clear(0)
if board_config.BOARD_TYPE == 'WAVESHARE_RLCD':
display.text("Exiting test...", 15, 60, 1)
display.text("Rebooting to normal...", 15, 80, 1)
else:
display.text("Exiting test...", 10, 50, 1)
display.text("Rebooting to normal...", 10, 70, 1)
display.show()
time.sleep(1)
try:
import os
os.remove("run_loopback.txt")
except:
pass
import machine
machine.reset()
time.sleep_ms(30)
print("Recording started! Speak into the microphone...")
if display:
display.clear(0)
if board_config.BOARD_TYPE == 'WAVESHARE_RLCD':
display.text("RLCD Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 390, 20, 1)
display.text("RECORDING: 10 seconds...", 15, 80, 1)
display.text("Speak into microphone!", 15, 100, 1)
else:
display.text("Touch Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 310, 20, 1)
display.text("RECORDING: 10 seconds...", 10, 60, 1)
display.text("Speak now!", 10, 80, 1)
display.show()
# 1. Start MCLK PWM using board config parameters
mclk_pwm = None
if board_config.audio_mclk_pin is not None:
mclk_pin = Pin(board_config.audio_mclk_pin, Pin.OUT)
mclk_pwm = machine.PWM(mclk_pin)
mclk_pwm.freq(board_config.audio_mclk_freq)
mclk_pwm.duty_u16(32768)
# 2. Configure I2S RX (Stereo 16kHz) - ibuf set to 16000 for safety
i2s_rx = I2S(1,
sck=Pin(board_config.audio_i2s_sck),
ws=Pin(board_config.audio_i2s_ws),
sd=Pin(board_config.audio_i2s_rx_sd),
mode=I2S.RX,
ibuf=16000,
rate=16000,
bits=16,
format=I2S.STEREO)
# 3. Wake up and configure the microphone chip (ES7210 vs ES8311)
init_ok = False
if board_config.audio_mic_codec == "ES7210":
from audio_util import ES7210
mic_adc = ES7210(board_config.i2c_bus)
init_ok = mic_adc.init(sample_rate=16000, bit_width=16)
else:
from audio_util import ES8311
mic_adc = ES8311(board_config.i2c_bus)
if mic_adc.init(sample_rate=16000):
init_ok = True
mic_adc.set_volume(80)
try:
mic_adc._write(0x14, 0x1A) # Enable analog mic input & PGA
mic_adc._write(0x16, 0x01) # Enable +6dB gain boost
mic_adc._write(0x17, 0xC8) # Set ADC digital volume
except:
pass
if not init_ok:
print("Microphone codec initialization failed! Aborting recording.")
i2s_rx.deinit()
if mclk_pwm:
mclk_pwm.deinit()
if display:
display.clear(0)
display.text("Codec Init Failed!", 15, 80, 1)
display.show()
time.sleep(3)
continue
# Record loop to RAM - using ticks_ms for safe timing
buffer = bytearray(2048)
audio_chunks = []
total_bytes = 0
start_rec_time = time.ticks_ms()
max_duration_ms = 10000 # 10 seconds
try:
while time.ticks_diff(time.ticks_ms(), start_rec_time) < max_duration_ms:
bytes_read = i2s_rx.readinto(buffer)
if bytes_read > 0:
audio_chunks.append(bytes(buffer[:bytes_read]))
total_bytes += bytes_read
except Exception as e:
print("Recording failed:", e)
finally:
i2s_rx.deinit()
if mclk_pwm:
mclk_pwm.deinit()
print(f"Recorded {total_bytes} bytes in RAM ({len(audio_chunks)} chunks).")
# Wait for release of key/trigger to debounce
time.sleep_ms(200)
# 4. Playback from RAM
if display:
display.clear(0)
if board_config.BOARD_TYPE == 'WAVESHARE_RLCD':
display.text("RLCD Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 390, 20, 1)
display.text("PLAYING BACK RESPONSE...", 15, 80, 1)
display.text(f"Bytes: {total_bytes}", 15, 100, 1)
else:
display.text("Touch Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 310, 20, 1)
display.text("PLAYING BACK RESPONSE...", 10, 60, 1)
display.text(f"Bytes: {total_bytes}", 10, 80, 1)
display.show()
play_ram_pcm(audio_chunks, channels=2, rate=16000, bits=16, volume=95)
if display:
display.clear(0)
if board_config.BOARD_TYPE == 'WAVESHARE_RLCD':
display.text("RLCD Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 390, 20, 1)
display.text("Playback Finished!", 15, 70, 1)
display.text("Release trigger to restart...", 15, 95, 1)
else:
display.text("Touch Audio Loopback Test", 10, 10, 1)
display.line(10, 20, 310, 20, 1)
display.text("Playback Finished!", 10, 50, 1)
display.text("Release trigger to restart...", 10, 75, 1)
display.show()
# Wait for release of button/touch to debounce before ready again
while is_talk_trigger_active():
time.sleep_ms(30)
time.sleep_ms(500)
if __name__ == "__main__":
main()