Files
mcp_screen/demo_audio_loopback.py
T

232 lines
9.1 KiB
Python

import time
import machine
from machine import Pin, I2S
import board_config
import audio_util
def play_raw_pcm(filename, 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 '{filename}'...")
with open(filename, 'rb') as f:
buf = bytearray(2048)
while True:
bytes_read = f.readinto(buf)
if bytes_read == 0:
break
i2s.write(buf[:bytes_read])
except Exception as e:
print("Error during raw 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 Audio Loopback Utility Script ===")
print(f"Board Detected: {board_config.BOARD_TYPE}")
# Initialize buttons using polling Pins instead of BoardButtons class (to avoid edge-triggered interrupt storms)
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
filename = "local_audio_test.pcm"
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...", 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...", 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()
# We record as long as the button is pressed (or up to 10 seconds max)
# 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)
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=8000,
rate=16000,
bits=16,
format=I2S.STEREO)
# 3. Wake up and configure the microphone chip (ES7210 vs ES8311)
if board_config.audio_mic_codec == "ES7210":
from audio_util import ES7210
mic_adc = ES7210(board_config.i2c_bus)
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):
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
# Record loop
buffer = bytearray(1024)
total_bytes = 0
start_rec_time = time.time()
try:
with open(filename, 'wb') as f:
while (time.time() - start_rec_time) < 10:
bytes_read = i2s_rx.readinto(buffer)
if bytes_read > 0:
f.write(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 to '{filename}'.")
# Wait for release of key/trigger to debounce
time.sleep_ms(200)
# 4. Playback
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_raw_pcm(filename, 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()