From 6ff5e7a370115ab1cd3467450abe1583df243871 Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 09:41:36 -0700 Subject: [PATCH 01/23] fix soundd long duration playback and mic feedback --- selfdrive/ui/soundd.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 8225efabf9af5a..a6f5d2fc27999b 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -110,6 +110,8 @@ def get_sound_data(self, frames): # get "frames" worth of data from the current ret[written_frames:written_frames+frames_to_write] = sound_data[current_sound_frame:current_sound_frame+frames_to_write] written_frames += frames_to_write self.current_sound_frame += frames_to_write + current_sound_frame = self.current_sound_frame % len(sound_data) + loops = self.current_sound_frame // len(sound_data) return ret * self.current_volume @@ -119,7 +121,7 @@ def callback(self, data_out: np.ndarray, frames: int, time, status) -> None: data_out[:frames, 0] = self.get_sound_data(frames) def update_alert(self, new_alert): - current_alert_played_once = self.current_alert == AudibleAlert.none or self.current_sound_frame > len(self.loaded_sounds[self.current_alert]) + current_alert_played_once = self.current_alert == AudibleAlert.none or self.current_sound_frame >= len(self.loaded_sounds[self.current_alert]) if self.current_alert != new_alert and (new_alert != AudibleAlert.none or current_alert_played_once): if new_alert == AudibleAlert.warningImmediate: self.ramp_start_volume = self.current_volume @@ -162,10 +164,11 @@ def soundd_thread(self): while True: sm.update(0) - # Always update volume, even when alert is playing + # freeze volume during alerts to avoid mic feedback increasing volume if sm.updated['soundPressure']: self.spl_filter_weighted.update(sm["soundPressure"].soundPressureWeightedDb) - self.current_volume = self.calculate_volume(float(self.spl_filter_weighted.x)) + if self.current_alert == AudibleAlert.none: + self.current_volume = self.calculate_volume(float(self.spl_filter_weighted.x)) self.get_audible_alert(sm) From d82a36bee9b8e8723aba7b5973927bc18010eede Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 11:30:55 -0700 Subject: [PATCH 02/23] new sounds --- selfdrive/assets/sounds/chime.wav | 3 +++ selfdrive/assets/sounds/disengage.wav | 4 ++-- selfdrive/assets/sounds/engage.wav | 4 ++-- selfdrive/assets/sounds/prompt.wav | 4 ++-- selfdrive/assets/sounds/prompt_distracted.wav | 4 ++-- selfdrive/assets/sounds/refuse.wav | 4 ++-- selfdrive/assets/sounds/warning_immediate.wav | 4 ++-- selfdrive/assets/sounds/warning_soft.wav | 4 ++-- selfdrive/ui/soundd.py | 2 ++ 9 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 selfdrive/assets/sounds/chime.wav diff --git a/selfdrive/assets/sounds/chime.wav b/selfdrive/assets/sounds/chime.wav new file mode 100644 index 00000000000000..a5472df0657bf4 --- /dev/null +++ b/selfdrive/assets/sounds/chime.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4cd499f0635cae6e09d427a9abac29478ba09c5d770f95cccf8a2d0b70ea7fc +size 83350 diff --git a/selfdrive/assets/sounds/disengage.wav b/selfdrive/assets/sounds/disengage.wav index 7bfd97ad715e2e..4311cd41052cd1 100644 --- a/selfdrive/assets/sounds/disengage.wav +++ b/selfdrive/assets/sounds/disengage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42bd04a57b527c787a0555503e02a203f7d672c12d448769a3f41f17befbf013 -size 48044 +oid sha256:dc73d1c42a9dfd7f7ab151ea936929d7f1d46d044eb0c0c6526a7aef07253132 +size 83350 diff --git a/selfdrive/assets/sounds/engage.wav b/selfdrive/assets/sounds/engage.wav index 8633b5ac2d82b1..128eb7d8bcde9b 100644 --- a/selfdrive/assets/sounds/engage.wav +++ b/selfdrive/assets/sounds/engage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1e177499d9439367179cc57a6301b6162393972e3a136cc35c5fdac026bf10a -size 48044 +oid sha256:00aa91fa5c159d1ad5293faea0893ad1875bb79246fceb785a7c35fe341ab90e +size 83350 diff --git a/selfdrive/assets/sounds/prompt.wav b/selfdrive/assets/sounds/prompt.wav index e482c85a629806..415d6b1574c4e0 100644 --- a/selfdrive/assets/sounds/prompt.wav +++ b/selfdrive/assets/sounds/prompt.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad19268e4aaaeac8dd21f6b26c16a121e7b3f50bba867748e7226727643ae682 -size 144642 +oid sha256:bf80796f87f6aae013f2486b5c292c6abcdf47ea3d167be6a419f4dd63461aba +size 62700 diff --git a/selfdrive/assets/sounds/prompt_distracted.wav b/selfdrive/assets/sounds/prompt_distracted.wav index 750d580f04827d..3b8911aa9b344b 100644 --- a/selfdrive/assets/sounds/prompt_distracted.wav +++ b/selfdrive/assets/sounds/prompt_distracted.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1810ad0418ac234f02dec005883c8f0e1c3e0e5ece7a3157803c5a66cb8e5adc -size 85662 +oid sha256:b5fd38394e570fbd79bdd96bbe3b3b872d0c25017996c5cc38a35152b48072e5 +size 73026 diff --git a/selfdrive/assets/sounds/refuse.wav b/selfdrive/assets/sounds/refuse.wav index 1e0c47697d89cb..719582f55c09e6 100644 --- a/selfdrive/assets/sounds/refuse.wav +++ b/selfdrive/assets/sounds/refuse.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4af81cbf1d96a42cc351878b015298aee82874b46baaf1a615ca91ec36c0ced6 -size 83228 +oid sha256:b5283aec51c3057bd6a4b872bd4ad59180bcca443b1c132aa9c062b9e1e17211 +size 83350 diff --git a/selfdrive/assets/sounds/warning_immediate.wav b/selfdrive/assets/sounds/warning_immediate.wav index fcbfed79ed87d6..afe60941357797 100644 --- a/selfdrive/assets/sounds/warning_immediate.wav +++ b/selfdrive/assets/sounds/warning_immediate.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5a390831afca3bfc6ea3c2739b872ebf866e70df8ae30653f8587e5cd3993959 -size 68306 +oid sha256:df9557871ca191f51c45bff53c24f772b306519b9d06d7fa36a0e242363af873 +size 52374 diff --git a/selfdrive/assets/sounds/warning_soft.wav b/selfdrive/assets/sounds/warning_soft.wav index 7db30303d60f5d..af54aac78c142d 100644 --- a/selfdrive/assets/sounds/warning_soft.wav +++ b/selfdrive/assets/sounds/warning_soft.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67e636d072703e6b1233a12344c0a6304fd43d64dbb31c66b71c2c8870a339c1 -size 153764 +oid sha256:27e539051557c80265a06681b3d316f90f58e7c21dbfd3a1690c2b537926fea7 +size 62700 diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index a6f5d2fc27999b..6ea71842c0f8e2 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -45,6 +45,8 @@ AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME), AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), + + AudibleAlert.laneChange: ("bump.wav", 1, MAX_VOLUME), } if HARDWARE.get_device_type() == "tizi": sound_list.update({ From a0c7dba22e41231b44e0802f23f4f738f1169294 Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 11:54:34 -0700 Subject: [PATCH 03/23] redefine AudibleAlert --- cereal/log.capnp | 20 ++++++++++++++++++- selfdrive/selfdrived/events.py | 8 ++++---- .../ui/mici/onroad/driver_camera_dialog.py | 4 ++-- selfdrive/ui/soundd.py | 6 +++--- selfdrive/ui/tests/test_soundd.py | 4 ++-- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index b7202dfcf7a36c..e224211b9394ec 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -771,13 +771,31 @@ struct SelfdriveState { alertStatus @5 :AlertStatus; alertSize @6 :AlertSize; alertType @7 :Text; - alertSound @8 :Car.CarControl.HUDControl.AudibleAlert; + alertSoundDEPRECATED @8 :Car.CarControl.HUDControl.AudibleAlert; + alertSound @13 :AudibleAlert; alertHudVisual @12 :Car.CarControl.HUDControl.VisualAlert; # configurable driving settings experimentalMode @10 :Bool; personality @11 :LongitudinalPersonality; + enum AudibleAlert { + none @0; + + engage @1; + disengage @2; + refuse @3; + + warningSoft @4; + warningImmediate @5; + + prompt @6; + promptRepeat @7; + promptDistracted @8; + + laneChange @9; + } + enum OpenpilotState @0xdbe58b96d2d1ac61 { disabled @0; preEnabled @1; diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py index 99e25571bd1136..b9185cd0880567 100755 --- a/selfdrive/selfdrived/events.py +++ b/selfdrive/selfdrived/events.py @@ -18,7 +18,7 @@ AlertSize = log.SelfdriveState.AlertSize AlertStatus = log.SelfdriveState.AlertStatus VisualAlert = car.CarControl.HUDControl.VisualAlert -AudibleAlert = car.CarControl.HUDControl.AudibleAlert +AudibleAlert = log.SelfdriveState.AudibleAlert EventName = log.OnroadEvent.EventName @@ -117,7 +117,7 @@ def __init__(self, alert_size: log.SelfdriveState.AlertSize, priority: Priority, visual_alert: car.CarControl.HUDControl.VisualAlert, - audible_alert: car.CarControl.HUDControl.AudibleAlert, + audible_alert: log.SelfdriveState.AudibleAlert, duration: float, creation_delay: float = 0.): @@ -182,7 +182,7 @@ def __init__(self, alert_text_2: str): class EngagementAlert(Alert): - def __init__(self, audible_alert: car.CarControl.HUDControl.AudibleAlert): + def __init__(self, audible_alert: log.SelfdriveState.AudibleAlert): super().__init__("", "", AlertStatus.normal, AlertSize.none, Priority.MID, VisualAlert.none, @@ -609,7 +609,7 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin "Changing Lanes", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.none, .1), + Priority.LOW, VisualAlert.none, AudibleAlert.laneChange, .1), }, EventName.steerSaturated: { diff --git a/selfdrive/ui/mici/onroad/driver_camera_dialog.py b/selfdrive/ui/mici/onroad/driver_camera_dialog.py index df5afe2e7c4a7f..696d37bed8591d 100644 --- a/selfdrive/ui/mici/onroad/driver_camera_dialog.py +++ b/selfdrive/ui/mici/onroad/driver_camera_dialog.py @@ -1,5 +1,5 @@ import pyray as rl -from cereal import car, log, messaging +from cereal import log, messaging from msgq.visionipc import VisionStreamType from openpilot.selfdrive.ui.mici.onroad.cameraview import CameraView from openpilot.selfdrive.ui.mici.onroad.driver_state import DriverStateRenderer @@ -104,7 +104,7 @@ def _publish_alert_sound(self, dm_state): if self._pm is None: return - AudibleAlert = car.CarControl.HUDControl.AudibleAlert + AudibleAlert = log.SelfdriveState.AudibleAlert ALERT_SOUNDS = { 'two': AudibleAlert.promptDistracted, 'three': AudibleAlert.warningImmediate, diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 6ea71842c0f8e2..e1de3dd4171675 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -4,7 +4,7 @@ import wave -from cereal import car, messaging +from cereal import log, messaging from openpilot.common.basedir import BASEDIR from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.realtime import Ratekeeper @@ -30,7 +30,7 @@ AMBIENT_DB = 30 VOLUME_BASE = 10 -AudibleAlert = car.CarControl.HUDControl.AudibleAlert +AudibleAlert = log.SelfdriveState.AudibleAlert sound_list: dict[int, tuple[str, int | None, float]] = { @@ -46,7 +46,7 @@ AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME), AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), - AudibleAlert.laneChange: ("bump.wav", 1, MAX_VOLUME), + AudibleAlert.laneChange: ("chime.wav", 1, MAX_VOLUME), } if HARDWARE.get_device_type() == "tizi": sound_list.update({ diff --git a/selfdrive/ui/tests/test_soundd.py b/selfdrive/ui/tests/test_soundd.py index a9da8455ebdd24..a4aa053c188f5a 100644 --- a/selfdrive/ui/tests/test_soundd.py +++ b/selfdrive/ui/tests/test_soundd.py @@ -1,11 +1,11 @@ -from cereal import car +from cereal import log from cereal import messaging from cereal.messaging import SubMaster, PubMaster from openpilot.selfdrive.ui.soundd import SELFDRIVE_STATE_TIMEOUT, check_selfdrive_timeout_alert import time -AudibleAlert = car.CarControl.HUDControl.AudibleAlert +AudibleAlert = log.SelfdriveState.AudibleAlert class TestSoundd: From a608519bfd574c106d8c6405d8682697a35b1103 Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 12:17:14 -0700 Subject: [PATCH 04/23] chg alertSound2 --- cereal/log.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index e224211b9394ec..20755f58cfd1fa 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -936,7 +936,7 @@ struct ControlsState @0x97ff69c53601abf1 { alertStatus @38 :SelfdriveState.AlertStatus; alertSize @39 :SelfdriveState.AlertSize; alertType @44 :Text; - alertSound2 @56 :Car.CarControl.HUDControl.AudibleAlert; + alertSound2 @56 :SelfdriveState.AudibleAlert; engageable @41 :Bool; # can OP be engaged? state @31 :SelfdriveState.OpenpilotState; enabled @19 :Bool; From b6119b3383b10f5fecfa2b15f48537a3c1c25a14 Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 14:01:37 -0700 Subject: [PATCH 05/23] rn laneChange --- cereal/log.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index 20755f58cfd1fa..cc5797c135f8a7 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -793,7 +793,7 @@ struct SelfdriveState { promptRepeat @7; promptDistracted @8; - laneChange @9; + laneChangeConfirmed @9; } enum OpenpilotState @0xdbe58b96d2d1ac61 { From 3f175a2fa49964f4d0f287a3560c699187b06123 Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 14:39:16 -0700 Subject: [PATCH 06/23] fix --- selfdrive/selfdrived/events.py | 2 +- selfdrive/ui/soundd.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py index b9185cd0880567..1ca3c29937d996 100755 --- a/selfdrive/selfdrived/events.py +++ b/selfdrive/selfdrived/events.py @@ -609,7 +609,7 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin "Changing Lanes", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.laneChange, .1), + Priority.LOW, VisualAlert.none, AudibleAlert.laneChangeConfirmed, .1), }, EventName.steerSaturated: { diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index e1de3dd4171675..970dbf029cb783 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -46,7 +46,7 @@ AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME), AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), - AudibleAlert.laneChange: ("chime.wav", 1, MAX_VOLUME), + AudibleAlert.laneChangeConfirmed: ("chime.wav", 1, MAX_VOLUME), } if HARDWARE.get_device_type() == "tizi": sound_list.update({ From d6bb423e6530065f680024bd8740429bc201f93e Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 16:49:08 -0700 Subject: [PATCH 07/23] exp cutoff --- selfdrive/assets/sounds/prompt.wav | 2 +- selfdrive/assets/sounds/warning_immediate.wav | 2 +- selfdrive/assets/sounds/warning_soft.wav | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/assets/sounds/prompt.wav b/selfdrive/assets/sounds/prompt.wav index 415d6b1574c4e0..1a1c3beac26807 100644 --- a/selfdrive/assets/sounds/prompt.wav +++ b/selfdrive/assets/sounds/prompt.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf80796f87f6aae013f2486b5c292c6abcdf47ea3d167be6a419f4dd63461aba +oid sha256:712a0cc14a81044f10643e8e68f542379ab3509ae8340ca80e1aa8dc74989689 size 62700 diff --git a/selfdrive/assets/sounds/warning_immediate.wav b/selfdrive/assets/sounds/warning_immediate.wav index afe60941357797..f1655acb4c58a7 100644 --- a/selfdrive/assets/sounds/warning_immediate.wav +++ b/selfdrive/assets/sounds/warning_immediate.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df9557871ca191f51c45bff53c24f772b306519b9d06d7fa36a0e242363af873 +oid sha256:a30d0d96fb1f6565c6f8dcf49131ebcc84b65e3251bf0143fc61a527d5908939 size 52374 diff --git a/selfdrive/assets/sounds/warning_soft.wav b/selfdrive/assets/sounds/warning_soft.wav index af54aac78c142d..5b75eb4bea700c 100644 --- a/selfdrive/assets/sounds/warning_soft.wav +++ b/selfdrive/assets/sounds/warning_soft.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27e539051557c80265a06681b3d316f90f58e7c21dbfd3a1690c2b537926fea7 +oid sha256:0b908d6ea546e35d964c61f003e81c55fbf0fa418487a4e4564c2112941ef281 size 62700 From 3626076a1500a7635fd6e4a643e4203eae664ed7 Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 18:16:15 -0700 Subject: [PATCH 08/23] no sound cutoff --- selfdrive/ui/soundd.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 970dbf029cb783..4ccebd74e14fe4 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -76,6 +76,7 @@ def __init__(self): self.ramp_start_time = 0. self.selfdrive_timeout_alert = False + self.pending_stop = False self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) @@ -114,6 +115,10 @@ def get_sound_data(self, frames): # get "frames" worth of data from the current self.current_sound_frame += frames_to_write current_sound_frame = self.current_sound_frame % len(sound_data) loops = self.current_sound_frame // len(sound_data) + if self.pending_stop and current_sound_frame == 0: + self.current_alert = AudibleAlert.none + self.pending_stop = False + break return ret * self.current_volume @@ -123,6 +128,11 @@ def callback(self, data_out: np.ndarray, frames: int, time, status) -> None: data_out[:frames, 0] = self.get_sound_data(frames) def update_alert(self, new_alert): + # let looping sounds complete instead of cutting off when there is no new alert pending + if new_alert == AudibleAlert.none and self.current_alert != AudibleAlert.none and sound_list[self.current_alert][1] is None: + self.pending_stop = True + return + self.pending_stop = False current_alert_played_once = self.current_alert == AudibleAlert.none or self.current_sound_frame >= len(self.loaded_sounds[self.current_alert]) if self.current_alert != new_alert and (new_alert != AudibleAlert.none or current_alert_played_once): if new_alert == AudibleAlert.warningImmediate: From 1256930ce1c28218c0e0367b56babf0475db605e Mon Sep 17 00:00:00 2001 From: elkoled Date: Tue, 9 Jun 2026 18:22:13 -0700 Subject: [PATCH 09/23] fadeout --- selfdrive/assets/sounds/warning_immediate.wav | 4 ++-- selfdrive/assets/sounds/warning_soft.wav | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/assets/sounds/warning_immediate.wav b/selfdrive/assets/sounds/warning_immediate.wav index f1655acb4c58a7..c0991f2af4111a 100644 --- a/selfdrive/assets/sounds/warning_immediate.wav +++ b/selfdrive/assets/sounds/warning_immediate.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a30d0d96fb1f6565c6f8dcf49131ebcc84b65e3251bf0143fc61a527d5908939 -size 52374 +oid sha256:c72cf1c8df57577efc9bf0f0a0840d9fb59cb734c3bb6e5513dbef0d9c831d52 +size 51560 diff --git a/selfdrive/assets/sounds/warning_soft.wav b/selfdrive/assets/sounds/warning_soft.wav index 5b75eb4bea700c..96173e918d0c4d 100644 --- a/selfdrive/assets/sounds/warning_soft.wav +++ b/selfdrive/assets/sounds/warning_soft.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b908d6ea546e35d964c61f003e81c55fbf0fa418487a4e4564c2112941ef281 -size 62700 +oid sha256:31319358b184a928f3c43c5e7c246050ceb19fbed1f40c417bb7d19e51e71b3f +size 61846 From 5fc57a6d1bc062e3eefd3e416534f3b4a87d54d0 Mon Sep 17 00:00:00 2001 From: elkoled Date: Wed, 10 Jun 2026 11:20:41 -0700 Subject: [PATCH 10/23] rename --- cereal/log.capnp | 7 +++++-- selfdrive/selfdrived/events.py | 2 +- selfdrive/ui/soundd.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index cc5797c135f8a7..bc4ad9b10e5d1a 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -771,7 +771,6 @@ struct SelfdriveState { alertStatus @5 :AlertStatus; alertSize @6 :AlertSize; alertType @7 :Text; - alertSoundDEPRECATED @8 :Car.CarControl.HUDControl.AudibleAlert; alertSound @13 :AudibleAlert; alertHudVisual @12 :Car.CarControl.HUDControl.VisualAlert; @@ -793,7 +792,7 @@ struct SelfdriveState { promptRepeat @7; promptDistracted @8; - laneChangeConfirmed @9; + confirmation @9; } enum OpenpilotState @0xdbe58b96d2d1ac61 { @@ -816,6 +815,10 @@ struct SelfdriveState { mid @2; full @3; } + + deprecated :group { + alertSound @8 :Car.CarControl.HUDControl.AudibleAlert; + } } struct ControlsState @0x97ff69c53601abf1 { diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py index 1ca3c29937d996..8748b263db9051 100755 --- a/selfdrive/selfdrived/events.py +++ b/selfdrive/selfdrived/events.py @@ -609,7 +609,7 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin "Changing Lanes", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.laneChangeConfirmed, .1), + Priority.LOW, VisualAlert.none, AudibleAlert.confirmation, .1), }, EventName.steerSaturated: { diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 4ccebd74e14fe4..9052a801c3587f 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -46,7 +46,7 @@ AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME), AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), - AudibleAlert.laneChangeConfirmed: ("chime.wav", 1, MAX_VOLUME), + AudibleAlert.confirmation: ("chime.wav", 1, MAX_VOLUME), } if HARDWARE.get_device_type() == "tizi": sound_list.update({ From 6e09e0bf68da3317ec0e58c046958ac285fbc8ef Mon Sep 17 00:00:00 2001 From: elkoled Date: Wed, 10 Jun 2026 15:07:10 -0700 Subject: [PATCH 11/23] update soft warning --- selfdrive/assets/sounds/warning_soft.wav | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/assets/sounds/warning_soft.wav b/selfdrive/assets/sounds/warning_soft.wav index 96173e918d0c4d..7f0d17186cfca9 100644 --- a/selfdrive/assets/sounds/warning_soft.wav +++ b/selfdrive/assets/sounds/warning_soft.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:31319358b184a928f3c43c5e7c246050ceb19fbed1f40c417bb7d19e51e71b3f -size 61846 +oid sha256:4b1fb84224372518f5a79d243fdacfa39509d0e91cb161a77ccbd634724f530d +size 62700 From 1510072a86128c3a5e5ead19860fa7500649f597 Mon Sep 17 00:00:00 2001 From: elkoled Date: Wed, 10 Jun 2026 16:06:23 -0700 Subject: [PATCH 12/23] laneChangeStarted event --- cereal/log.capnp | 1 + selfdrive/selfdrived/events.py | 10 +++++++++- selfdrive/selfdrived/selfdrived.py | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index bc4ad9b10e5d1a..2fdae4ef3784b7 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -89,6 +89,7 @@ struct OnroadEvent @0xc4fa6047f024e718 { stockAeb @52; stockLkas @98; lateralManeuver @99; + laneChangeStarted @100; ldw @53; carUnrecognized @54; invalidLkasSetting @55; diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py index 8748b263db9051..c6a82aed6cc5ce 100755 --- a/selfdrive/selfdrived/events.py +++ b/selfdrive/selfdrived/events.py @@ -609,7 +609,15 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin "Changing Lanes", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.confirmation, .1), + Priority.LOW, VisualAlert.none, AudibleAlert.none, .1), + }, + + EventName.laneChangeStarted: { + ET.WARNING: Alert( + "", + "", + AlertStatus.normal, AlertSize.none, + Priority.MID, VisualAlert.none, AudibleAlert.confirmation, .2), }, EventName.steerSaturated: { diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index d2fd0f099e0299..3dc8971355b7ab 100755 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -293,6 +293,9 @@ def update_events(self, CS): self.events.add(EventName.preLaneChangeRight) elif self.sm['modelV2'].meta.laneChangeState in (LaneChangeState.laneChangeStarting, LaneChangeState.laneChangeFinishing): + # one-off event to prevent lanechange alert from being played repeatedly during lanechange + if EventName.laneChange not in self.events_prev: + self.events.add(EventName.laneChangeStarted) self.events.add(EventName.laneChange) for i, pandaState in enumerate(self.sm['pandaStates']): From db84aeae22296750f33030ea21f00cfb153a0b51 Mon Sep 17 00:00:00 2001 From: elkoled Date: Wed, 10 Jun 2026 18:32:14 -0700 Subject: [PATCH 13/23] raise floor to 22 --- selfdrive/ui/soundd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 9052a801c3587f..dd486ffe2f3eba 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -22,7 +22,7 @@ SELFDRIVE_STATE_TIMEOUT = 5 # 5 seconds FILTER_DT = 1. / (micd.SAMPLE_RATE / micd.FFT_SAMPLES) -AMBIENT_DB = 24 # DB where MIN_VOLUME is applied +AMBIENT_DB = 22 # DB where MIN_VOLUME is applied DB_SCALE = 30 # AMBIENT_DB + DB_SCALE is where MAX_VOLUME is applied VOLUME_BASE = 20 From 6ffbd6de2b931f3da07c918da1321c232f94c323 Mon Sep 17 00:00:00 2001 From: elkoled Date: Thu, 11 Jun 2026 07:20:05 -0700 Subject: [PATCH 14/23] single tone sounds --- selfdrive/assets/sounds/disengage.wav | 2 +- selfdrive/assets/sounds/engage.wav | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/assets/sounds/disengage.wav b/selfdrive/assets/sounds/disengage.wav index 4311cd41052cd1..ac298ede79bad2 100644 --- a/selfdrive/assets/sounds/disengage.wav +++ b/selfdrive/assets/sounds/disengage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc73d1c42a9dfd7f7ab151ea936929d7f1d46d044eb0c0c6526a7aef07253132 +oid sha256:8adc04b7983e58e6fcfaf89a2d6e318b87b9eb923ed1e819d028d76d288fe6ca size 83350 diff --git a/selfdrive/assets/sounds/engage.wav b/selfdrive/assets/sounds/engage.wav index 128eb7d8bcde9b..36a97efad22e8d 100644 --- a/selfdrive/assets/sounds/engage.wav +++ b/selfdrive/assets/sounds/engage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00aa91fa5c159d1ad5293faea0893ad1875bb79246fceb785a7c35fe341ab90e +oid sha256:f4cf683258d75ec30d64d2c1c5644849d4fc99412330cd89aace71bf0b59c960 size 83350 From 5da41f1fe0829e8154af29c19945aa491991191e Mon Sep 17 00:00:00 2001 From: elkoled Date: Thu, 11 Jun 2026 19:48:53 -0700 Subject: [PATCH 15/23] pre alert --- selfdrive/assets/sounds/disengage.wav | 4 ++-- selfdrive/assets/sounds/engage.wav | 4 ++-- selfdrive/assets/sounds/pre_alert.wav | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 selfdrive/assets/sounds/pre_alert.wav diff --git a/selfdrive/assets/sounds/disengage.wav b/selfdrive/assets/sounds/disengage.wav index ac298ede79bad2..74a7ea52ef7a06 100644 --- a/selfdrive/assets/sounds/disengage.wav +++ b/selfdrive/assets/sounds/disengage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8adc04b7983e58e6fcfaf89a2d6e318b87b9eb923ed1e819d028d76d288fe6ca -size 83350 +oid sha256:f4136ea734f28a8b7b87b65dbed3423ca1a0835dee35452aed5e9b93b8b59d23 +size 73026 diff --git a/selfdrive/assets/sounds/engage.wav b/selfdrive/assets/sounds/engage.wav index 36a97efad22e8d..b28eceff77aa1f 100644 --- a/selfdrive/assets/sounds/engage.wav +++ b/selfdrive/assets/sounds/engage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4cf683258d75ec30d64d2c1c5644849d4fc99412330cd89aace71bf0b59c960 -size 83350 +oid sha256:8bb3b7ce07671df3df1877e508ac46866d1571a2feea2ad05ae84264df48f298 +size 73026 diff --git a/selfdrive/assets/sounds/pre_alert.wav b/selfdrive/assets/sounds/pre_alert.wav new file mode 100644 index 00000000000000..4443bf7d23425b --- /dev/null +++ b/selfdrive/assets/sounds/pre_alert.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c0af7f5fe57bb36ab96fae868e20feca763541c97a61b3a3a84a0e7fcb81163 +size 83350 From 13b2144324497484db898b22f33898001be21061 Mon Sep 17 00:00:00 2001 From: elkoled Date: Thu, 11 Jun 2026 19:54:48 -0700 Subject: [PATCH 16/23] try pre alert --- cereal/log.capnp | 1 + selfdrive/selfdrived/events.py | 4 ++-- selfdrive/ui/mici/onroad/driver_camera_dialog.py | 1 + selfdrive/ui/soundd.py | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index 2fdae4ef3784b7..159306fd2caec0 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -794,6 +794,7 @@ struct SelfdriveState { promptDistracted @8; confirmation @9; + preAlert @10; } enum OpenpilotState @0xdbe58b96d2d1ac61 { diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py index c6a82aed6cc5ce..c65bc1cdcfdba5 100755 --- a/selfdrive/selfdrived/events.py +++ b/selfdrive/selfdrived/events.py @@ -517,7 +517,7 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin "Pay Attention", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.none, .1), + Priority.LOW, VisualAlert.none, AudibleAlert.preAlert, .1), }, EventName.driverDistracted2: { @@ -1045,7 +1045,7 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin "Pay Attention", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.none, 2), + Priority.LOW, VisualAlert.none, AudibleAlert.preAlert, 2), }, EventName.driverDistracted2: { ET.PERMANENT: Alert( diff --git a/selfdrive/ui/mici/onroad/driver_camera_dialog.py b/selfdrive/ui/mici/onroad/driver_camera_dialog.py index 696d37bed8591d..8761f5df5eee32 100644 --- a/selfdrive/ui/mici/onroad/driver_camera_dialog.py +++ b/selfdrive/ui/mici/onroad/driver_camera_dialog.py @@ -106,6 +106,7 @@ def _publish_alert_sound(self, dm_state): AudibleAlert = log.SelfdriveState.AudibleAlert ALERT_SOUNDS = { + 'one': AudibleAlert.preAlert, 'two': AudibleAlert.promptDistracted, 'three': AudibleAlert.warningImmediate, } diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index dd486ffe2f3eba..322be01c9c5b53 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -47,6 +47,7 @@ AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), AudibleAlert.confirmation: ("chime.wav", 1, MAX_VOLUME), + AudibleAlert.preAlert: ("pre_alert.wav", 1, MAX_VOLUME), } if HARDWARE.get_device_type() == "tizi": sound_list.update({ From bfc8346e562eca79e4b6766d5cb67b786a3e3d80 Mon Sep 17 00:00:00 2001 From: elkoled Date: Fri, 12 Jun 2026 09:05:55 -0700 Subject: [PATCH 17/23] update prompt sounds --- selfdrive/assets/sounds/prompt.wav | 4 ++-- selfdrive/assets/sounds/prompt_distracted.wav | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/assets/sounds/prompt.wav b/selfdrive/assets/sounds/prompt.wav index 1a1c3beac26807..5433850bd3da25 100644 --- a/selfdrive/assets/sounds/prompt.wav +++ b/selfdrive/assets/sounds/prompt.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:712a0cc14a81044f10643e8e68f542379ab3509ae8340ca80e1aa8dc74989689 -size 62700 +oid sha256:7569fbf911a25225d79eee6a78e6e2ea26559b7e1eb28840b1090d9855e0ade8 +size 63300 diff --git a/selfdrive/assets/sounds/prompt_distracted.wav b/selfdrive/assets/sounds/prompt_distracted.wav index 3b8911aa9b344b..c11993f20c0442 100644 --- a/selfdrive/assets/sounds/prompt_distracted.wav +++ b/selfdrive/assets/sounds/prompt_distracted.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5fd38394e570fbd79bdd96bbe3b3b872d0c25017996c5cc38a35152b48072e5 +oid sha256:412ef25d2fb103c1ebd55c667313a5921493305fb4e1f4e1dafc08d3b95d86ab size 73026 From 6dce3a82e996c011f7b8cd6a096ebaaa812e8d62 Mon Sep 17 00:00:00 2001 From: elkoled Date: Fri, 12 Jun 2026 15:01:10 -0700 Subject: [PATCH 18/23] update prompt sound --- selfdrive/assets/sounds/prompt.wav | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/assets/sounds/prompt.wav b/selfdrive/assets/sounds/prompt.wav index 5433850bd3da25..75f3087c238a4c 100644 --- a/selfdrive/assets/sounds/prompt.wav +++ b/selfdrive/assets/sounds/prompt.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7569fbf911a25225d79eee6a78e6e2ea26559b7e1eb28840b1090d9855e0ade8 -size 63300 +oid sha256:cc588f2679ce236ccd49d996f671d74a4d7c624d886260fa3d9ae6e71480b9f8 +size 73026 From 3788b1db3acf06e04e3ff5613789b10ce8fd67c2 Mon Sep 17 00:00:00 2001 From: elkoled Date: Fri, 12 Jun 2026 15:01:31 -0700 Subject: [PATCH 19/23] add dual sound toggle --- common/params_keys.h | 1 + selfdrive/assets/sounds/dual_disengage.wav | 3 +++ selfdrive/assets/sounds/dual_engage.wav | 3 +++ selfdrive/ui/layouts/settings/developer.py | 12 +++++++++++ .../ui/mici/layouts/settings/developer.py | 2 ++ selfdrive/ui/soundd.py | 21 +++++++++++++++++-- 6 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 selfdrive/assets/sounds/dual_disengage.wav create mode 100644 selfdrive/assets/sounds/dual_engage.wav diff --git a/common/params_keys.h b/common/params_keys.h index 7a96da0be792b9..9b0e6d9f43ac15 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -37,6 +37,7 @@ inline static std::unordered_map keys = { {"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}}, {"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}}, {"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}}, + {"DualToneSounds", {PERSISTENT, BOOL}}, {"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY, BOOL}}, {"ExperimentalMode", {PERSISTENT, BOOL}}, {"ExperimentalModeConfirmed", {PERSISTENT, BOOL}}, diff --git a/selfdrive/assets/sounds/dual_disengage.wav b/selfdrive/assets/sounds/dual_disengage.wav new file mode 100644 index 00000000000000..74a7ea52ef7a06 --- /dev/null +++ b/selfdrive/assets/sounds/dual_disengage.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4136ea734f28a8b7b87b65dbed3423ca1a0835dee35452aed5e9b93b8b59d23 +size 73026 diff --git a/selfdrive/assets/sounds/dual_engage.wav b/selfdrive/assets/sounds/dual_engage.wav new file mode 100644 index 00000000000000..b28eceff77aa1f --- /dev/null +++ b/selfdrive/assets/sounds/dual_engage.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8bb3b7ce07671df3df1877e508ac46866d1571a2feea2ad05ae84264df48f298 +size 73026 diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py index 64179093223155..1c857075df6480 100644 --- a/selfdrive/ui/layouts/settings/developer.py +++ b/selfdrive/ui/layouts/settings/developer.py @@ -88,6 +88,13 @@ def __init__(self): initial_state=self._params.get_bool("ShowDebugInfo"), callback=self._on_enable_ui_debug, ) + + self._dual_tone_toggle = toggle_item( + lambda: tr("Dual Tone Sounds"), + description="", + initial_state=self._params.get_bool("DualToneSounds"), + callback=self._on_dual_tone_sounds, + ) self._on_enable_ui_debug(self._params.get_bool("ShowDebugInfo")) self._scroller = Scroller([ @@ -99,6 +106,7 @@ def __init__(self): self._lat_maneuver_toggle, self._alpha_long_toggle, self._ui_debug_toggle, + self._dual_tone_toggle, ], line_separator=True, spacing=0) # Toggles should be not available to change in onroad state @@ -146,9 +154,13 @@ def _update_toggles(self): ("LateralManeuverMode", self._lat_maneuver_toggle), ("AlphaLongitudinalEnabled", self._alpha_long_toggle), ("ShowDebugInfo", self._ui_debug_toggle), + ("DualToneSounds", self._dual_tone_toggle), ): item.action_item.set_state(self._params.get_bool(key)) + def _on_dual_tone_sounds(self, state: bool): + self._params.put_bool("DualToneSounds", state, block=True) + def _on_enable_ui_debug(self, state: bool): self._params.put_bool("ShowDebugInfo", state, block=True) gui_app.set_show_touches(state) diff --git a/selfdrive/ui/mici/layouts/settings/developer.py b/selfdrive/ui/mici/layouts/settings/developer.py index 2f0250ff5f269e..1d4cf81d4d4601 100644 --- a/selfdrive/ui/mici/layouts/settings/developer.py +++ b/selfdrive/ui/mici/layouts/settings/developer.py @@ -82,6 +82,7 @@ def ssh_keys_callback(): self._alpha_long_toggle = BigToggle("alpha longitudinal", initial_state=ui_state.params.get_bool("AlphaLongitudinalEnabled"), toggle_callback=self._on_alpha_long_enabled) + self._dual_tone_toggle = BigParamControl("dual tone sounds", "DualToneSounds") self._debug_mode_toggle = BigParamControl("ui debug mode", "ShowDebugInfo", toggle_callback=lambda checked: (gui_app.set_show_touches(checked), gui_app.set_show_fps(checked))) @@ -95,6 +96,7 @@ def ssh_keys_callback(): self._lat_maneuver_toggle, self._alpha_long_toggle, self._debug_mode_toggle, + self._dual_tone_toggle, ]) # Toggle lists diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 322be01c9c5b53..a5994fe8cd596d 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -7,6 +7,7 @@ from cereal import log, messaging from openpilot.common.basedir import BASEDIR from openpilot.common.filter_simple import FirstOrderFilter +from openpilot.common.params import Params from openpilot.common.realtime import Ratekeeper from openpilot.common.utils import retry from openpilot.common.swaglog import cloudlog @@ -32,6 +33,8 @@ AudibleAlert = log.SelfdriveState.AudibleAlert +DUAL_TONE_SOUNDS = {"engage.wav": "dual_engage.wav", "disengage.wav": "dual_disengage.wav"} + sound_list: dict[int, tuple[str, int | None, float]] = { # AudibleAlert, file name, play count (none for infinite) @@ -67,6 +70,8 @@ def check_selfdrive_timeout_alert(sm): class Soundd: def __init__(self): + self.params = Params() + self.dual_tone_sounds = self.params.get_bool("DualToneSounds") self.load_sounds() self.current_alert = AudibleAlert.none @@ -82,11 +87,13 @@ def __init__(self): self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) def load_sounds(self): - self.loaded_sounds: dict[int, np.ndarray] = {} + loaded_sounds: dict[int, np.ndarray] = {} # Load all sounds for sound in sound_list: filename, play_count, volume = sound_list[sound] + if self.dual_tone_sounds: + filename = DUAL_TONE_SOUNDS.get(filename, filename) with wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r') as wavefile: assert wavefile.getnchannels() == 1 @@ -94,7 +101,10 @@ def load_sounds(self): assert wavefile.getframerate() == SAMPLE_RATE length = wavefile.getnframes() - self.loaded_sounds[sound] = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2) + loaded_sounds[sound] = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2) + + # swap atomically: the audio callback reads this dict from another thread + self.loaded_sounds = loaded_sounds def get_sound_data(self, frames): # get "frames" worth of data from the current alert sound, looping when required @@ -185,6 +195,13 @@ def soundd_thread(self): self.get_audible_alert(sm) + # check once per second if the sound set changed + if rk.frame % 20 == 0: + dual_tone_sounds = self.params.get_bool("DualToneSounds") + if dual_tone_sounds != self.dual_tone_sounds: + self.dual_tone_sounds = dual_tone_sounds + self.load_sounds() + # Ramp up immediate warning sound over 4s if self.current_alert == AudibleAlert.warningImmediate: elapsed = time.monotonic() - self.ramp_start_time From a9ce8a9634daad17fbf51ae21f36c141db297e5f Mon Sep 17 00:00:00 2001 From: elkoled Date: Fri, 12 Jun 2026 15:45:40 -0700 Subject: [PATCH 20/23] move toggle --- selfdrive/assets/sounds/disengage.wav | 4 ++-- selfdrive/assets/sounds/engage.wav | 4 ++-- selfdrive/ui/layouts/settings/developer.py | 2 +- selfdrive/ui/mici/layouts/settings/developer.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/selfdrive/assets/sounds/disengage.wav b/selfdrive/assets/sounds/disengage.wav index 74a7ea52ef7a06..ac298ede79bad2 100644 --- a/selfdrive/assets/sounds/disengage.wav +++ b/selfdrive/assets/sounds/disengage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4136ea734f28a8b7b87b65dbed3423ca1a0835dee35452aed5e9b93b8b59d23 -size 73026 +oid sha256:8adc04b7983e58e6fcfaf89a2d6e318b87b9eb923ed1e819d028d76d288fe6ca +size 83350 diff --git a/selfdrive/assets/sounds/engage.wav b/selfdrive/assets/sounds/engage.wav index b28eceff77aa1f..36a97efad22e8d 100644 --- a/selfdrive/assets/sounds/engage.wav +++ b/selfdrive/assets/sounds/engage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bb3b7ce07671df3df1877e508ac46866d1571a2feea2ad05ae84264df48f298 -size 73026 +oid sha256:f4cf683258d75ec30d64d2c1c5644849d4fc99412330cd89aace71bf0b59c960 +size 83350 diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py index 1c857075df6480..9f1d8ad40f9bcd 100644 --- a/selfdrive/ui/layouts/settings/developer.py +++ b/selfdrive/ui/layouts/settings/developer.py @@ -98,6 +98,7 @@ def __init__(self): self._on_enable_ui_debug(self._params.get_bool("ShowDebugInfo")) self._scroller = Scroller([ + self._dual_tone_toggle, self._adb_toggle, self._ssh_toggle, self._ssh_keys, @@ -106,7 +107,6 @@ def __init__(self): self._lat_maneuver_toggle, self._alpha_long_toggle, self._ui_debug_toggle, - self._dual_tone_toggle, ], line_separator=True, spacing=0) # Toggles should be not available to change in onroad state diff --git a/selfdrive/ui/mici/layouts/settings/developer.py b/selfdrive/ui/mici/layouts/settings/developer.py index 1d4cf81d4d4601..9640308b8a7c83 100644 --- a/selfdrive/ui/mici/layouts/settings/developer.py +++ b/selfdrive/ui/mici/layouts/settings/developer.py @@ -88,6 +88,7 @@ def ssh_keys_callback(): gui_app.set_show_fps(checked))) self._scroller.add_widgets([ + self._dual_tone_toggle, self._adb_toggle, self._ssh_toggle, self._ssh_keys_btn, @@ -96,7 +97,6 @@ def ssh_keys_callback(): self._lat_maneuver_toggle, self._alpha_long_toggle, self._debug_mode_toggle, - self._dual_tone_toggle, ]) # Toggle lists From 361b6a67403c9565f2cd41a38d5b6395e2ba1a17 Mon Sep 17 00:00:00 2001 From: elkoled Date: Fri, 12 Jun 2026 16:00:35 -0700 Subject: [PATCH 21/23] rename --- common/params_keys.h | 2 +- selfdrive/ui/layouts/settings/developer.py | 16 ++++++++-------- selfdrive/ui/mici/layouts/settings/developer.py | 4 ++-- selfdrive/ui/soundd.py | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/common/params_keys.h b/common/params_keys.h index 9b0e6d9f43ac15..a9d14496468b89 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -37,7 +37,7 @@ inline static std::unordered_map keys = { {"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}}, {"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}}, {"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}}, - {"DualToneSounds", {PERSISTENT, BOOL}}, + {"SingleToneSounds", {PERSISTENT, BOOL}}, {"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY, BOOL}}, {"ExperimentalMode", {PERSISTENT, BOOL}}, {"ExperimentalModeConfirmed", {PERSISTENT, BOOL}}, diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py index 9f1d8ad40f9bcd..cfee77d6849b10 100644 --- a/selfdrive/ui/layouts/settings/developer.py +++ b/selfdrive/ui/layouts/settings/developer.py @@ -89,16 +89,16 @@ def __init__(self): callback=self._on_enable_ui_debug, ) - self._dual_tone_toggle = toggle_item( - lambda: tr("Dual Tone Sounds"), + self._single_tone_toggle = toggle_item( + lambda: tr("Single Tone Sounds"), description="", - initial_state=self._params.get_bool("DualToneSounds"), - callback=self._on_dual_tone_sounds, + initial_state=self._params.get_bool("SingleToneSounds"), + callback=self._on_single_tone_sounds, ) self._on_enable_ui_debug(self._params.get_bool("ShowDebugInfo")) self._scroller = Scroller([ - self._dual_tone_toggle, + self._single_tone_toggle, self._adb_toggle, self._ssh_toggle, self._ssh_keys, @@ -154,12 +154,12 @@ def _update_toggles(self): ("LateralManeuverMode", self._lat_maneuver_toggle), ("AlphaLongitudinalEnabled", self._alpha_long_toggle), ("ShowDebugInfo", self._ui_debug_toggle), - ("DualToneSounds", self._dual_tone_toggle), + ("SingleToneSounds", self._single_tone_toggle), ): item.action_item.set_state(self._params.get_bool(key)) - def _on_dual_tone_sounds(self, state: bool): - self._params.put_bool("DualToneSounds", state, block=True) + def _on_single_tone_sounds(self, state: bool): + self._params.put_bool("SingleToneSounds", state, block=True) def _on_enable_ui_debug(self, state: bool): self._params.put_bool("ShowDebugInfo", state, block=True) diff --git a/selfdrive/ui/mici/layouts/settings/developer.py b/selfdrive/ui/mici/layouts/settings/developer.py index 9640308b8a7c83..859368b7883a6e 100644 --- a/selfdrive/ui/mici/layouts/settings/developer.py +++ b/selfdrive/ui/mici/layouts/settings/developer.py @@ -82,13 +82,13 @@ def ssh_keys_callback(): self._alpha_long_toggle = BigToggle("alpha longitudinal", initial_state=ui_state.params.get_bool("AlphaLongitudinalEnabled"), toggle_callback=self._on_alpha_long_enabled) - self._dual_tone_toggle = BigParamControl("dual tone sounds", "DualToneSounds") + self._single_tone_toggle = BigParamControl("single tone sounds", "SingleToneSounds") self._debug_mode_toggle = BigParamControl("ui debug mode", "ShowDebugInfo", toggle_callback=lambda checked: (gui_app.set_show_touches(checked), gui_app.set_show_fps(checked))) self._scroller.add_widgets([ - self._dual_tone_toggle, + self._single_tone_toggle, self._adb_toggle, self._ssh_toggle, self._ssh_keys_btn, diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index a5994fe8cd596d..b89e55cd4e3d5a 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -71,7 +71,7 @@ def check_selfdrive_timeout_alert(sm): class Soundd: def __init__(self): self.params = Params() - self.dual_tone_sounds = self.params.get_bool("DualToneSounds") + self.single_tone_sounds = self.params.get_bool("SingleToneSounds") self.load_sounds() self.current_alert = AudibleAlert.none @@ -92,7 +92,7 @@ def load_sounds(self): # Load all sounds for sound in sound_list: filename, play_count, volume = sound_list[sound] - if self.dual_tone_sounds: + if not self.single_tone_sounds: filename = DUAL_TONE_SOUNDS.get(filename, filename) with wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r') as wavefile: @@ -197,9 +197,9 @@ def soundd_thread(self): # check once per second if the sound set changed if rk.frame % 20 == 0: - dual_tone_sounds = self.params.get_bool("DualToneSounds") - if dual_tone_sounds != self.dual_tone_sounds: - self.dual_tone_sounds = dual_tone_sounds + single_tone_sounds = self.params.get_bool("SingleToneSounds") + if single_tone_sounds != self.single_tone_sounds: + self.single_tone_sounds = single_tone_sounds self.load_sounds() # Ramp up immediate warning sound over 4s From 068480a519d8472737d1648aeb4d73279ef614ad Mon Sep 17 00:00:00 2001 From: elkoled Date: Mon, 15 Jun 2026 08:18:36 -0700 Subject: [PATCH 22/23] update prompt sound --- selfdrive/assets/sounds/prompt.wav | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/assets/sounds/prompt.wav b/selfdrive/assets/sounds/prompt.wav index 75f3087c238a4c..4c832a32245d48 100644 --- a/selfdrive/assets/sounds/prompt.wav +++ b/selfdrive/assets/sounds/prompt.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc588f2679ce236ccd49d996f671d74a4d7c624d886260fa3d9ae6e71480b9f8 +oid sha256:e8df0608f9ab3636c8f41b7413375a261cabff3be6c95c60f05f1cfd0fc723a8 size 73026 From 33d24402b004193f40d4f18527e4333e2876baa6 Mon Sep 17 00:00:00 2001 From: elkoled Date: Wed, 17 Jun 2026 13:58:32 -0700 Subject: [PATCH 23/23] add sound debug --- cereal/log.capnp | 8 ++++ cereal/services.py | 1 + common/params_keys.h | 1 + .../ui/mici/layouts/settings/developer.py | 2 + .../ui/mici/onroad/augmented_road_view.py | 4 ++ selfdrive/ui/mici/onroad/sound_debug.py | 43 +++++++++++++++++++ selfdrive/ui/soundd.py | 8 ++++ selfdrive/ui/ui_state.py | 1 + 8 files changed, 68 insertions(+) create mode 100644 selfdrive/ui/mici/onroad/sound_debug.py diff --git a/cereal/log.capnp b/cereal/log.capnp index 7d30a3da63e3d7..6630ffd1cbf96c 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -2454,6 +2454,13 @@ struct SoundPressure @0xdc24138990726023 { } } +struct SoundDebug { + volume @0 :Float32; + ambientDb @1 :Float32; + rawDb @2 :Float32; + alert @3 :SelfdriveState.AudibleAlert; +} + struct AudioData { data @0 :Data; sampleRate @1 :UInt32; @@ -2538,6 +2545,7 @@ struct Event { # microphone data soundPressure @103 :SoundPressure; rawAudioData @147 :AudioData; + soundDebug @152 :SoundDebug; # systems stuff androidLog @20 :AndroidLogEntry; diff --git a/cereal/services.py b/cereal/services.py index c2d38d852db133..44219c5e53959b 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -75,6 +75,7 @@ def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] "userBookmark": (True, 0., 1), "soundPressure": (True, 10., 10), "rawAudioData": (False, 20.), + "soundDebug": (False, 20.), "bookmarkButton": (True, 0., 1), "audioFeedback": (True, 0., 1), "roadEncodeData": (False, 20., None, QueueSize.BIG), diff --git a/common/params_keys.h b/common/params_keys.h index a9d14496468b89..ed64418875379a 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -112,6 +112,7 @@ inline static std::unordered_map keys = { {"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet {"SecOCKey", {PERSISTENT | DONT_LOG, STRING}}, {"ShowDebugInfo", {PERSISTENT, BOOL}}, + {"ShowSoundDebug", {PERSISTENT, BOOL}}, {"RouteCount", {PERSISTENT, INT, "0"}}, {"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"SshEnabled", {PERSISTENT, BOOL}}, diff --git a/selfdrive/ui/mici/layouts/settings/developer.py b/selfdrive/ui/mici/layouts/settings/developer.py index 8e0ba633b5df7b..36fad0995aead2 100644 --- a/selfdrive/ui/mici/layouts/settings/developer.py +++ b/selfdrive/ui/mici/layouts/settings/developer.py @@ -82,12 +82,14 @@ def ssh_keys_callback(): self._alpha_long_toggle = BigToggle("alpha longitudinal", initial_state=ui_state.params.get_bool("AlphaLongitudinalEnabled"), toggle_callback=self._on_alpha_long_enabled) + self._sound_debug_toggle = BigParamControl("show sound debug", "ShowSoundDebug") self._single_tone_toggle = BigParamControl("single tone sounds", "SingleToneSounds") self._debug_mode_toggle = BigParamControl("ui debug mode", "ShowDebugInfo", toggle_callback=lambda checked: (gui_app.set_show_touches(checked), gui_app.set_show_fps(checked))) self._scroller.add_widgets([ + self._sound_debug_toggle, self._single_tone_toggle, self._adb_toggle, self._ssh_toggle, diff --git a/selfdrive/ui/mici/onroad/augmented_road_view.py b/selfdrive/ui/mici/onroad/augmented_road_view.py index 0246a0e5973b9d..068cca1047a56d 100644 --- a/selfdrive/ui/mici/onroad/augmented_road_view.py +++ b/selfdrive/ui/mici/onroad/augmented_road_view.py @@ -9,6 +9,7 @@ from openpilot.selfdrive.ui.mici.onroad.hud_renderer import HudRenderer from openpilot.selfdrive.ui.mici.onroad.model_renderer import ModelRenderer from openpilot.selfdrive.ui.mici.onroad.confidence_ball import ConfidenceBall +from openpilot.selfdrive.ui.mici.onroad.sound_debug import SoundDebug from openpilot.selfdrive.ui.mici.onroad.cameraview import CameraView from openpilot.system.ui.lib.application import FontWeight, gui_app, MousePos, MouseEvent from openpilot.system.ui.widgets.label import UnifiedLabel @@ -151,6 +152,7 @@ def __init__(self, bookmark_callback=None, stream_type: VisionStreamType = Visio self._alert_renderer = AlertRenderer() self._driver_state_renderer = DriverStateRenderer() self._confidence_ball = ConfidenceBall() + self._sound_debug = SoundDebug() self._offroad_label = UnifiedLabel("start the car to\nuse openpilot", 54, FontWeight.DISPLAY, text_color=rl.Color(255, 255, 255, int(255 * 0.9)), alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER, @@ -243,6 +245,8 @@ def _render(self, _): self._bookmark_icon.render(self.rect) + self._sound_debug.render(self._content_rect) + def _switch_stream_if_needed(self, sm): if sm['selfdriveState'].experimentalMode and WIDE_CAM in self.available_streams: v_ego = sm['carState'].vEgo diff --git a/selfdrive/ui/mici/onroad/sound_debug.py b/selfdrive/ui/mici/onroad/sound_debug.py new file mode 100644 index 00000000000000..f9457b3b1fe19b --- /dev/null +++ b/selfdrive/ui/mici/onroad/sound_debug.py @@ -0,0 +1,43 @@ +import pyray as rl +from openpilot.common.params import Params +from openpilot.system.ui.lib.application import gui_app, FontWeight +from openpilot.system.ui.lib.text_measure import measure_text_cached +from openpilot.system.ui.widgets import Widget +from openpilot.selfdrive.ui.ui_state import ui_state + + +class SoundDebug(Widget): + def __init__(self): + super().__init__() + self._params = Params() + self._enabled = self._params.get_bool("ShowSoundDebug") + self._font = gui_app.font(FontWeight.MEDIUM) + + def _render(self, rect): + if gui_app.frame % 30 == 0: + self._enabled = self._params.get_bool("ShowSoundDebug") + if not self._enabled: + return + + sd = ui_state.sm["soundDebug"] + alert = str(sd.alert).split(".")[-1] + rows = [ + ("volume", f"{sd.volume * 100:.0f}%"), + ("ambient", f"{sd.ambientDb:.1f} dB"), + ("mic raw", f"{sd.rawDb:.1f} dB"), + ("alert", alert), + ] + fs, pad, gap, lh = 32, 14, 24, 40 + + label_w = max(measure_text_cached(self._font, lbl, fs).x for lbl, _ in rows) + value_w = max(measure_text_cached(self._font, val, fs).x for _, val in rows) + w = 2 * pad + label_w + gap + value_w + h = 2 * pad + lh * len(rows) + x0, y0 = rect.x + rect.width - w - 6, rect.y + 6 + + rl.draw_rectangle_rounded(rl.Rectangle(x0, y0, w, h), 0.12, 10, rl.Color(0, 0, 0, 210)) + for i, (label, value) in enumerate(rows): + y = y0 + pad + lh * i + rl.draw_text_ex(self._font, label, rl.Vector2(x0 + pad, y), fs, 0, rl.Color(170, 170, 170, 255)) + vx = x0 + w - pad - measure_text_cached(self._font, value, fs).x + rl.draw_text_ex(self._font, value, rl.Vector2(vx, y), fs, 0, rl.WHITE) diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index b89e55cd4e3d5a..9dfd4aca221876 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -179,6 +179,7 @@ def soundd_thread(self): import sounddevice as sd sm = messaging.SubMaster(['selfdriveState', 'soundPressure']) + pm = messaging.PubMaster(['soundDebug']) with self.get_stream(sd) as stream: rk = Ratekeeper(20) @@ -208,6 +209,13 @@ def soundd_thread(self): ramp_vol = float(np.interp(elapsed, [0, ALERT_RAMP_TIME], [self.ramp_start_volume, MAX_VOLUME])) self.current_volume = max(self.current_volume, ramp_vol) + msg = messaging.new_message('soundDebug', valid=True) + msg.soundDebug.volume = float(self.current_volume) + msg.soundDebug.ambientDb = float(self.spl_filter_weighted.x) + msg.soundDebug.rawDb = float(sm["soundPressure"].soundPressureWeightedDb) + msg.soundDebug.alert = self.current_alert + pm.send('soundDebug', msg) + rk.keep_time() assert stream.active diff --git a/selfdrive/ui/ui_state.py b/selfdrive/ui/ui_state.py index 6309642fd27436..f17e28e3d8ae65 100644 --- a/selfdrive/ui/ui_state.py +++ b/selfdrive/ui/ui_state.py @@ -58,6 +58,7 @@ def _initialize(self): "liveParameters", "testJoystick", "rawAudioData", + "soundDebug", ] )