# Standalone MicroPython Voice Animation: Speaking Mouth (Audio Spectrum) # Exposes run(text="", frames=...) and runs automatically if executed directly. import time import math try: import board_config display = getattr(board_config, 'display_instance', None) except Exception: board_config = None display = None def draw_center_text(d, msg, y, w, scale=1, c=1): char_w = 8 * scale x = max(0, (w - len(msg) * char_w) // 2) if hasattr(d, 'text_large') and scale > 1: try: d.text_large(msg, x, y, scale, c) return except Exception: pass d.text(msg, x, y, c) def run(text="", frames=100): if not display: print("board_config.display_instance is not available. Skipping animation.") return width = getattr(display, 'width', 400) height = getattr(display, 'height', 300) cx, cy = width // 2, height // 2 label = text if text else "SPEAKING..." frame = 0 try: while True: if frames is not None and frames > 0 and frame >= frames: break display.clear(0) # Draw top and bottom boundary lines for the sound waves display.line(cx - 100, cy - 45, cx + 100, cy - 45, 1) display.line(cx - 100, cy + 45, cx + 100, cy + 45, 1) # Draw a series of vertical equalizer bars modulated to simulate speech patterns # An envelope simulates words (peaks and silences) word_envelope = abs(math.sin(frame * 0.05)) num_bars = 15 bar_w = 8 gap = 4 total_w = num_bars * bar_w + (num_bars - 1) * gap start_x = cx - total_w // 2 for i in range(num_bars): bx = start_x + i * (bar_w + gap) # Modulate individual bar heights using frame phase offsets phase = frame * 0.28 + i * 0.45 noise_val = abs(math.sin(phase)) * 0.7 + abs(math.cos(phase * 1.5)) * 0.3 # Height peaks towards the center bars (bell shape) center_factor = math.cos(((i - num_bars // 2) / (num_bars // 2)) * (math.pi / 2.2)) h = int(6 + 72 * word_envelope * noise_val * center_factor) # Keep height within boundaries h = min(80, h) # Draw vertical bar centered at cy display.fill_rect(bx, cy - h // 2, bar_w, h, 1) # Draw centered text label at the bottom draw_center_text(display, label, height - 30, width, scale=1, c=1) display.show() frame += 1 try: time.sleep_ms(50) except AttributeError: time.sleep(0.05) except KeyboardInterrupt: print("Animation interrupted by user.") if __name__ in ('__main__', '__name__'): run()