mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-09-07 16:13:42 +08:00
fade
This commit is contained in:
@@ -11,7 +11,8 @@ AUDIO_DIR = Path("/data/media/0/custom_audio")
|
||||
SAMPLE_RATE = 48000
|
||||
MAX_SECONDS = 300
|
||||
GEAR_TIMEOUT = 0.5
|
||||
RESUME_FRAMES = int(0.15 * SAMPLE_RATE)
|
||||
DUCK_FRAMES = int(0.05 * SAMPLE_RATE)
|
||||
RESTORE_FRAMES = int(0.15 * SAMPLE_RATE)
|
||||
|
||||
|
||||
class GearTransition:
|
||||
@@ -54,7 +55,6 @@ class AudioPlayer:
|
||||
self.samples = np.empty(0, dtype=np.float32)
|
||||
self.position = 0
|
||||
self.gain = 1.0
|
||||
self.paused = False
|
||||
|
||||
def render(self, frames, alert_active):
|
||||
command = self.command
|
||||
@@ -63,23 +63,15 @@ class AudioPlayer:
|
||||
self.samples = command if command is not None else np.empty(0, dtype=np.float32)
|
||||
self.position = 0
|
||||
self.gain = 1.0
|
||||
self.paused = False
|
||||
out = np.zeros(frames, dtype=np.float32)
|
||||
if self.position == len(self.samples):
|
||||
return out
|
||||
if alert_active:
|
||||
self.paused = True
|
||||
self.gain = 0.0
|
||||
return out
|
||||
if self.paused:
|
||||
self.paused = False
|
||||
self.gain = 0.0
|
||||
n = min(frames, len(self.samples) - self.position)
|
||||
gains = np.minimum(1, self.gain + np.arange(n) / RESUME_FRAMES)
|
||||
step = -0.5 / DUCK_FRAMES if alert_active else 0.5 / RESTORE_FRAMES
|
||||
gains = np.clip(self.gain + np.arange(n) * step, 0.5, 1.0)
|
||||
out[:n] = self.samples[self.position:self.position + n] * gains
|
||||
self.position += n
|
||||
if n:
|
||||
self.gain = float(gains[-1])
|
||||
self.gain = float(np.clip(self.gain + n * step, 0.5, 1.0))
|
||||
return out
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ Each gear change plays `<gear>.wav`: `park.wav`, `drive.wav`, `sport.wav`, `reve
|
||||
- Entering a gear starts its audio from the beginning at full volume, with no fade-in.
|
||||
- Changing gears cuts the previous audio without a fade-out. If the new file is missing or invalid, playback stays silent.
|
||||
- Returning to a previous gear restarts its audio from the beginning. Staying in the same gear does not replay it.
|
||||
- Safety alerts pause custom audio immediately. After the alert, it resumes from its saved position with a **150 ms fade-in**. Audio triggered during an alert waits, then fades in.
|
||||
- While any alert sounds, custom audio keeps playing and fades to **50% volume over 50 ms**. Afterward it fades back to full volume over **150 ms**.
|
||||
- Alert volume is unchanged. Custom audio may be reduced further to prevent clipping when both sounds are loud.
|
||||
- Startup and recovery from unknown/invalid gear data or data gaps establish a silent baseline.
|
||||
|
||||
No settings or dismiss control. Replace or remove files to change future playback.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import numpy as np
|
||||
|
||||
from openpilot.cereal import messaging
|
||||
from openpilot.selfdrive.ui.soundd import AudibleAlert, Soundd
|
||||
from openpilot.selfdrive.ui.soundd import Soundd
|
||||
from openpilot.sunnypilot.selfdrive.ui.custom_audio import CustomAudio
|
||||
|
||||
|
||||
@@ -12,12 +12,13 @@ class SounddSP(Soundd):
|
||||
self.gear_sock = messaging.sub_sock("carState", conflate=False)
|
||||
|
||||
def callback(self, data_out: np.ndarray, frames: int, time, status) -> None:
|
||||
alert_active = self.current_alert != AudibleAlert.none
|
||||
super().callback(data_out, frames, time, status)
|
||||
alert_active = alert_active or self.current_alert != AudibleAlert.none or bool(np.any(data_out[:frames, 0]))
|
||||
custom_data = self.custom_audio.player.render(frames, alert_active)
|
||||
if not alert_active:
|
||||
data_out[:frames, 0] = custom_data
|
||||
alert_data = data_out[:frames, 0]
|
||||
alert_peak = float(np.max(np.abs(alert_data)))
|
||||
custom_data = self.custom_audio.player.render(frames, alert_peak > 0)
|
||||
custom_peak = float(np.max(np.abs(custom_data)))
|
||||
gain = min(1.0, max(0.0, 1.0 - alert_peak) / max(custom_peak, 1e-9))
|
||||
alert_data += custom_data * gain
|
||||
|
||||
def get_audible_alert(self, sm):
|
||||
super().get_audible_alert(sm)
|
||||
|
||||
Reference in New Issue
Block a user