|
|
@ -21,67 +21,51 @@ void sigHandler(int s) { |
|
|
|
|
|
|
|
|
|
|
|
class Sound : public QObject { |
|
|
|
class Sound : public QObject { |
|
|
|
public: |
|
|
|
public: |
|
|
|
explicit Sound(QObject *parent = 0) { |
|
|
|
explicit Sound(QObject *parent = 0) : sm({"carState", "controlsState"}) { |
|
|
|
// TODO: merge again and add EQ in the amp config
|
|
|
|
// TODO: merge again and add EQ in the amp config
|
|
|
|
const QString sound_asset_path = Hardware::TICI() ? "../assets/sounds_tici/" : "../assets/sounds/"; |
|
|
|
const QString sound_asset_path = Hardware::TICI() ? "../assets/sounds_tici/" : "../assets/sounds/"; |
|
|
|
std::tuple<AudibleAlert, QString, bool> sound_list[] = { |
|
|
|
std::tuple<AudibleAlert, QString, bool> sound_list[] = { |
|
|
|
{AudibleAlert::CHIME_DISENGAGE, sound_asset_path + "disengaged.wav", false}, |
|
|
|
{AudibleAlert::CHIME_DISENGAGE, "disengaged.wav", false}, |
|
|
|
{AudibleAlert::CHIME_ENGAGE, sound_asset_path + "engaged.wav", false}, |
|
|
|
{AudibleAlert::CHIME_ENGAGE, "engaged.wav", false}, |
|
|
|
{AudibleAlert::CHIME_WARNING1, sound_asset_path + "warning_1.wav", false}, |
|
|
|
{AudibleAlert::CHIME_WARNING1, "warning_1.wav", false}, |
|
|
|
{AudibleAlert::CHIME_WARNING2, sound_asset_path + "warning_2.wav", false}, |
|
|
|
{AudibleAlert::CHIME_WARNING2, "warning_2.wav", false}, |
|
|
|
{AudibleAlert::CHIME_WARNING2_REPEAT, sound_asset_path + "warning_2.wav", true}, |
|
|
|
{AudibleAlert::CHIME_WARNING2_REPEAT, "warning_2.wav", true}, |
|
|
|
{AudibleAlert::CHIME_WARNING_REPEAT, sound_asset_path + "warning_repeat.wav", true}, |
|
|
|
{AudibleAlert::CHIME_WARNING_REPEAT, "warning_repeat.wav", true}, |
|
|
|
{AudibleAlert::CHIME_ERROR, sound_asset_path + "error.wav", false}, |
|
|
|
{AudibleAlert::CHIME_ERROR, "error.wav", false}, |
|
|
|
{AudibleAlert::CHIME_PROMPT, sound_asset_path + "error.wav", false} |
|
|
|
{AudibleAlert::CHIME_PROMPT, "error.wav", false}}; |
|
|
|
}; |
|
|
|
|
|
|
|
for (auto &[alert, fn, loops] : sound_list) { |
|
|
|
for (auto &[alert, fn, loops] : sound_list) { |
|
|
|
QSoundEffect *s = new QSoundEffect(this); |
|
|
|
QSoundEffect *s = new QSoundEffect(this); |
|
|
|
QObject::connect(s, &QSoundEffect::statusChanged, this, &Sound::checkStatus); |
|
|
|
QObject::connect(s, &QSoundEffect::statusChanged, [=]() { assert(s->status() != QSoundEffect::Error); }); |
|
|
|
s->setSource(QUrl::fromLocalFile(fn)); |
|
|
|
s->setSource(QUrl::fromLocalFile(sound_asset_path + fn)); |
|
|
|
sounds[alert] = {s, loops ? QSoundEffect::Infinite : 0}; |
|
|
|
sounds[alert] = {s, loops ? QSoundEffect::Infinite : 0}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sm = new SubMaster({"carState", "controlsState"}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QTimer *timer = new QTimer(this); |
|
|
|
QTimer *timer = new QTimer(this); |
|
|
|
QObject::connect(timer, &QTimer::timeout, this, &Sound::update); |
|
|
|
QObject::connect(timer, &QTimer::timeout, this, &Sound::update); |
|
|
|
timer->start(); |
|
|
|
timer->start(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
~Sound() { |
|
|
|
|
|
|
|
delete sm; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private slots: |
|
|
|
|
|
|
|
void checkStatus() { |
|
|
|
|
|
|
|
QSoundEffect *s = qobject_cast<QSoundEffect*>(sender()); |
|
|
|
|
|
|
|
assert(s->status() != QSoundEffect::Error); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void update() { |
|
|
|
void update() { |
|
|
|
sm->update(100); |
|
|
|
sm.update(100); |
|
|
|
if (sm->updated("carState")) { |
|
|
|
if (sm.updated("carState")) { |
|
|
|
// scale volume with speed
|
|
|
|
// scale volume with speed
|
|
|
|
volume = util::map_val((*sm)["carState"].getCarState().getVEgo(), 0.f, 20.f, |
|
|
|
float volume = util::map_val(sm["carState"].getCarState().getVEgo(), 0.f, 20.f, |
|
|
|
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME); |
|
|
|
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME); |
|
|
|
for (auto &[s, loops] : sounds) { |
|
|
|
for (auto &[s, loops] : sounds) { |
|
|
|
s->setVolume(std::round(100 * volume) / 100); |
|
|
|
s->setVolume(std::round(100 * volume) / 100); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (sm->updated("controlsState")) { |
|
|
|
if (sm.updated("controlsState")) { |
|
|
|
const cereal::ControlsState::Reader &cs = (*sm)["controlsState"].getControlsState(); |
|
|
|
setAlert(sm["controlsState"].getControlsState().getAlertSound()); |
|
|
|
setAlert({QString::fromStdString(cs.getAlertText1()), |
|
|
|
} else if (sm.rcv_frame("controlsState") > 0 && sm["controlsState"].getControlsState().getEnabled() && |
|
|
|
QString::fromStdString(cs.getAlertText2()), |
|
|
|
((nanos_since_boot() - sm.rcv_time("controlsState")) / 1e9 > CONTROLS_TIMEOUT)) { |
|
|
|
QString::fromStdString(cs.getAlertType()), |
|
|
|
setAlert(CONTROLS_UNRESPONSIVE_ALERT.sound); |
|
|
|
cs.getAlertSize(), cs.getAlertSound()}); |
|
|
|
|
|
|
|
} else if (sm->rcv_frame("controlsState") > 0 && (*sm)["controlsState"].getControlsState().getEnabled() && |
|
|
|
|
|
|
|
((nanos_since_boot() - sm->rcv_time("controlsState")) / 1e9 > CONTROLS_TIMEOUT)) { |
|
|
|
|
|
|
|
setAlert(CONTROLS_UNRESPONSIVE_ALERT); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void setAlert(Alert a) { |
|
|
|
void setAlert(AudibleAlert sound) { |
|
|
|
if (!alert.equal(a)) { |
|
|
|
if (current_sound_ != sound) { |
|
|
|
alert = a; |
|
|
|
current_sound_ = sound; |
|
|
|
// stop sounds
|
|
|
|
// stop sounds
|
|
|
|
for (auto &[s, loops] : sounds) { |
|
|
|
for (auto &[s, loops] : sounds) { |
|
|
|
// Only stop repeating sounds
|
|
|
|
// Only stop repeating sounds
|
|
|
@ -91,8 +75,8 @@ private slots: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// play sound
|
|
|
|
// play sound
|
|
|
|
if (alert.sound != AudibleAlert::NONE) { |
|
|
|
if (sound != AudibleAlert::NONE) { |
|
|
|
auto &[s, loops] = sounds[alert.sound]; |
|
|
|
auto &[s, loops] = sounds[sound]; |
|
|
|
s->setLoopCount(loops); |
|
|
|
s->setLoopCount(loops); |
|
|
|
s->play(); |
|
|
|
s->play(); |
|
|
|
} |
|
|
|
} |
|
|
@ -100,10 +84,9 @@ private slots: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
Alert alert; |
|
|
|
AudibleAlert current_sound_ = AudibleAlert::NONE; |
|
|
|
float volume = Hardware::MIN_VOLUME; |
|
|
|
|
|
|
|
QMap<AudibleAlert, QPair<QSoundEffect*, int>> sounds; |
|
|
|
QMap<AudibleAlert, QPair<QSoundEffect*, int>> sounds; |
|
|
|
SubMaster *sm; |
|
|
|
SubMaster sm; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv) { |
|
|
|
int main(int argc, char **argv) { |
|
|
|