soundd: mix ClearPilot ding alongside alerts; add ding.wav
Adds the ding sound effect that fires on speed-limit changes / cruise- warning transitions (writers will set ClearpilotPlayDing="1" in /dev/shm/params; soundd polls at ~2Hz, clears the flag, plays once). The ding plays at MAX_VOLUME independent of the alert volume map and mixes into the same output stream. Single-shot — no looping. Loaded once at startup; failure to load just disables the ding (rest of soundd keeps working). print-to-stderr, not cloudlog (CLAUDE.md rule).
This commit is contained in:
Binary file not shown.
+45
-1
@@ -93,6 +93,29 @@ class Soundd:
|
|||||||
|
|
||||||
self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False)
|
self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False)
|
||||||
|
|
||||||
|
# CLEARPILOT ding (plays independently of alerts; triggered by writers
|
||||||
|
# setting ClearpilotPlayDing="1" in /dev/shm/params).
|
||||||
|
self.ding_sound = None
|
||||||
|
self.ding_frame = 0
|
||||||
|
self.ding_playing = False
|
||||||
|
self.ding_check_counter = 0
|
||||||
|
self._load_ding()
|
||||||
|
|
||||||
|
def _load_ding(self):
|
||||||
|
import sys
|
||||||
|
ding_path = BASEDIR + "/selfdrive/clearpilot/sounds/ding.wav"
|
||||||
|
try:
|
||||||
|
wavefile = wave.open(ding_path, 'r')
|
||||||
|
assert wavefile.getnchannels() == 1
|
||||||
|
assert wavefile.getsampwidth() == 2
|
||||||
|
assert wavefile.getframerate() == SAMPLE_RATE
|
||||||
|
length = wavefile.getnframes()
|
||||||
|
self.ding_sound = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2)
|
||||||
|
print(f"CLP soundd: ClearPilot ding loaded: {length} frames", file=sys.stderr, flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"CLP soundd: failed to load ding sound: {e}", file=sys.stderr, flush=True)
|
||||||
|
self.ding_sound = None
|
||||||
|
|
||||||
def load_sounds(self):
|
def load_sounds(self):
|
||||||
self.loaded_sounds: dict[int, np.ndarray] = {}
|
self.loaded_sounds: dict[int, np.ndarray] = {}
|
||||||
|
|
||||||
@@ -137,7 +160,20 @@ class Soundd:
|
|||||||
written_frames += frames_to_write
|
written_frames += frames_to_write
|
||||||
self.current_sound_frame += frames_to_write
|
self.current_sound_frame += frames_to_write
|
||||||
|
|
||||||
return ret * self.current_volume
|
ret = ret * self.current_volume
|
||||||
|
|
||||||
|
# CLEARPILOT: mix in ding (independent of alerts, always max volume)
|
||||||
|
if self.ding_playing and self.ding_sound is not None:
|
||||||
|
ding_remaining = len(self.ding_sound) - self.ding_frame
|
||||||
|
if ding_remaining > 0:
|
||||||
|
frames_to_write = min(ding_remaining, frames)
|
||||||
|
ret[:frames_to_write] += self.ding_sound[self.ding_frame:self.ding_frame + frames_to_write] * MAX_VOLUME
|
||||||
|
self.ding_frame += frames_to_write
|
||||||
|
else:
|
||||||
|
self.ding_playing = False
|
||||||
|
self.ding_frame = 0
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def callback(self, data_out: np.ndarray, frames: int, time, status) -> None:
|
def callback(self, data_out: np.ndarray, frames: int, time, status) -> None:
|
||||||
if status:
|
if status:
|
||||||
@@ -205,6 +241,14 @@ class Soundd:
|
|||||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||||
self.update_frogpilot_params()
|
self.update_frogpilot_params()
|
||||||
|
|
||||||
|
# CLEARPILOT: poll ClearpilotPlayDing at ~2Hz; clear it on read.
|
||||||
|
self.ding_check_counter += 1
|
||||||
|
if self.ding_check_counter % 10 == 0 and self.ding_sound is not None:
|
||||||
|
if self.params_memory.get("ClearpilotPlayDing") == b"1":
|
||||||
|
self.params_memory.put("ClearpilotPlayDing", "0")
|
||||||
|
self.ding_playing = True
|
||||||
|
self.ding_frame = 0
|
||||||
|
|
||||||
def update_frogpilot_params(self):
|
def update_frogpilot_params(self):
|
||||||
self.alert_volume_control = self.params.get_bool("AlertVolumeControl")
|
self.alert_volume_control = self.params.get_bool("AlertVolumeControl")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user