juno.sound

Audio playback via AVAudioPlayer.

Two entry shapes:

  • play() is fire-and-forget — start an audio file playing and return immediately. The player releases itself automatically when playback finishes, so users don’t have to manage anything.

  • Player is the stateful form for scripts that need control over the playback lifecycle (pause / seek / volume). It’s a context manager; use with blocks or call Player.close() explicitly to release the underlying AVAudioPlayer deterministically — __del__ is a best-effort safety net only.

Typical usage:

from juno import sound

# Fire-and-forget
sound.play("/path/to/notification.wav")

# Stateful — full control
with sound.Player("/path/to/song.mp3") as p:
    p.volume = 0.7
    p.play()
    time.sleep(2.0)
    p.pause()
    print(p.position, "of", p.duration)
    p.seek(0)
    p.play()

Notes:

  • Path validation is intentionally minimal at the Python layer — AVAudioPlayer surfaces format / decoding errors directly.

  • A Player instance is not thread-safe by itself; a script driving one Player from multiple threads must add its own synchronisation.

class juno.sound.Player(path)

Bases: object

A long-lived AVAudioPlayer wrapper.

Construct with a filesystem path; the file is loaded immediately. Call play() to start, pause() to pause without resetting, stop() to reset to position 0. The instance must be released by calling close() (or via a with block); __del__ is a best-effort fallback. Forgetting to close Player instances keeps the underlying audio resource alive until the script’s process exits.

Parameters:

path (str)

close()

Release the underlying handle. Idempotent — calling twice is fine; the second call is a no-op.

Return type:

None

play()

Start (or resume from pause) playback.

Raises:

RuntimeError – If the player is closed, or AVAudioPlayer.play() rejected the call (e.g. audio session was claimed by another app).

Return type:

None

pause()

Pause playback without resetting the position.

Return type:

None

stop()

Stop playback and reset the position to 0.

Return type:

None

seek(seconds)

Move the playhead to seconds.

Out-of-range values are clamped to [0, duration] by AVAudioPlayer silently. Negative seconds are accepted on input (Apple’s behaviour) but typically clamp to 0.

Parameters:

seconds (float) – Target position in seconds.

Raises:

TypeError – If seconds is not a real number.

Return type:

None

property duration: float

Total length of the loaded asset in seconds.

property position: float

Current playback position in seconds.

property is_playing: bool

True if playback is currently progressing.

property volume: float

Volume in the range [0.0, 1.0].

juno.sound.play(path)

Start playing path and return immediately.

The native player keeps itself alive until playback finishes (or fails), at which point its handle is automatically released. Useful for short notification sounds where the caller doesn’t need to control the playback lifecycle.

Parameters:

path (str) – Filesystem path to an audio file readable by AVAudioPlayer (any of the formats Core Audio supports — m4a, mp3, wav, aac, …).

Raises:
  • TypeError – If path is not a string.

  • ValueError – If path is empty.

  • RuntimeError – If the file could not be loaded or playback could not start (Core Audio rejects the format, audio session unavailable, etc.).

Return type:

None