Reachy Mini documentation

Sound Playback

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Sound Playback

This example demonstrates two ways to play audio through Reachy Mini’s speaker:

  • --wav: Play a WAV file using the play_sound() API.
  • --live: Push a continuous sine tone using the low-level push_audio_sample() API, useful for real-time audio sources such as text-to-speech engines or microphone input.

Usage:

# Play a wav file
python sound_play.py --wav /path/to/file.wav --backend webrtc

# Push a continuous sine tone (Ctrl+C to stop)
python sound_play.py --live --backend webrtc --tone-hz 440

Options:

  • --wav <path>: Path to a WAV file to play.
  • --live: Push a continuous sine tone.
  • --tone-hz <freq>: Sine wave frequency in Hz (--live mode only, default: 440).
  • --backend: Media backend to use (default_no_video, gstreamer_no_video, or webrtc).

import argparse
import logging
import os
import time

import numpy as np

from reachy_mini import ReachyMini


def play_wav(mini: "ReachyMini", wav_path: str) -> None:
    """Play a wav file using the media play_sound API."""
    wav_path = os.path.abspath(wav_path)
    print(f"Playing {wav_path}...")
    mini.media.play_sound(wav_path)
    time.sleep(2)  # wait a bit for the sound to finish
    print("Playback finished.")


def play_live_tone(mini: "ReachyMini", tone_hz: float) -> None:
    """Push a continuous sine tone to the speaker."""
    sample_rate = mini.media.get_output_audio_samplerate()
    chunk_duration = 0.02  # 20 ms chunks
    samples_per_chunk = int(sample_rate * chunk_duration)
    phase = 0.0

    mini.media.start_playing()
    print(f"Playing {tone_hz} Hz tone (Ctrl+C to stop)...")
    try:
        while True:
            t = np.arange(samples_per_chunk, dtype=np.float32) / sample_rate
            mono = 0.5 * np.sin(2.0 * np.pi * tone_hz * t + phase).astype(np.float32)
            phase += 2.0 * np.pi * tone_hz * samples_per_chunk / sample_rate
            mini.media.push_audio_sample(mono)
            time.sleep(0.01)
    except KeyboardInterrupt:
        print("\nStopping tone.")
    finally:
        mini.media.stop_playing()


def main(backend: str, wav_path: str | None, tone_hz: float) -> None:
    """Run the sound playback example."""
    logging.basicConfig(
        level=logging.DEBUG, format="%(asctime)s [%(levelname)s] %(message)s"
    )

    with ReachyMini(log_level="DEBUG", media_backend=backend) as mini:
        if wav_path:
            play_wav(mini, wav_path)
        else:
            play_live_tone(mini, tone_hz)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Plays audio on Reachy Mini's speaker."
    )
    parser.add_argument(
        "--backend",
        type=str,
        choices=["default_no_video", "gstreamer_no_video", "webrtc"],
        default="default_no_video",
        help="Media backend to use.",
    )

    mode = parser.add_mutually_exclusive_group(required=True)
    mode.add_argument(
        "--wav",
        type=str,
        help="Path to a wav file to play.",
    )
    mode.add_argument(
        "--live",
        action="store_true",
        help="Push a continuous sine tone.",
    )

    parser.add_argument(
        "--tone-hz",
        default=440.0,
        type=float,
        help="Sine wave frequency in Hz (--live mode only).",
    )

    args = parser.parse_args()
    main(backend=args.backend, wav_path=args.wav, tone_hz=args.tone_hz)
Update on GitHub