# 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:**
```bash
# 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`, `local`, or `webrtc`).

```python

import argparse
import os
import time
import wave

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)

    with wave.open(wav_path, "rb") as wf:
        wav_duration = wf.getnframes() / mini.media.get_output_audio_samplerate()
    time.sleep(wav_duration)
    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."""
    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", "local", "webrtc"],
        default="default",
        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)
```

