From 7346d050790b9f5e0800a740d029c53bd8a32d8c Mon Sep 17 00:00:00 2001 From: Dima Govorukha Date: Sun, 8 Mar 2020 09:43:46 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BA=D1=80=D0=B8=D0=B2=D1=8B=D1=85=20=D1=81=D0=BA?= =?UTF-8?q?=D0=BE=D1=80=D0=BE=D1=81=D1=82=D0=B8(VolumeCurves)=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B7=D0=B2=D1=83=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/vl60/vl60k/include/vl60.h | 2 +- addons/vl60/vl60k/src/vl60-init.cpp | 24 ++++++------ addons/vl60/vl60k/src/vl60-step.cpp | 32 +--------------- addons/vl60/vl60pk/include/vl60.h | 2 +- addons/vl60/vl60pk/src/vl60-init.cpp | 24 ++++++------ addons/vl60/vl60pk/src/vl60-step.cpp | 32 +--------------- .../sound-manager/include/sound-config.h | 1 + .../sound-manager/include/sound-manager.h | 2 + simulator/sound-manager/src/sound-manager.cpp | 38 +++++++++++++++++++ simulator/train/src/train.cpp | 1 + simulator/vehicle/include/vehicle.h | 2 + viewer/viewer/src/viewer.cpp | 2 - 12 files changed, 74 insertions(+), 88 deletions(-) diff --git a/addons/vl60/vl60k/include/vl60.h b/addons/vl60/vl60k/include/vl60.h index 701f7e7b..984a93b7 100644 --- a/addons/vl60/vl60k/include/vl60.h +++ b/addons/vl60/vl60k/include/vl60.h @@ -62,7 +62,7 @@ class VL60k : public Vehicle }; /// Список звуков перестука - QMap tap_sounds; + QList tap_sounds; float pant1_pos; float pant2_pos; diff --git a/addons/vl60/vl60k/src/vl60-init.cpp b/addons/vl60/vl60k/src/vl60-init.cpp index 751ef5bf..1869c325 100644 --- a/addons/vl60/vl60k/src/vl60-init.cpp +++ b/addons/vl60/vl60k/src/vl60-init.cpp @@ -214,18 +214,18 @@ void VL60k::initTriggers() void VL60k::initTapSounds() { QString f_p = "tap_"; - tap_sounds.insert(5, f_p + "5-10"); - tap_sounds.insert(10, f_p + "10-20"); - tap_sounds.insert(20, f_p + "20-30"); - tap_sounds.insert(30, f_p + "30-40"); - tap_sounds.insert(40, f_p + "40-50"); - tap_sounds.insert(50, f_p + "50-60"); - tap_sounds.insert(60, f_p + "60-70"); - tap_sounds.insert(70, f_p + "70-80"); - tap_sounds.insert(80, f_p + "80-90"); - tap_sounds.insert(90, f_p + "90-100"); - tap_sounds.insert(100, f_p + "100-110"); - tap_sounds.insert(110, f_p + "110-~"); + tap_sounds << (f_p + "5-10"); + tap_sounds << (f_p + "10-20"); + tap_sounds << (f_p + "20-30"); + tap_sounds << (f_p + "30-40"); + tap_sounds << (f_p + "40-50"); + tap_sounds << (f_p + "50-60"); + tap_sounds << (f_p + "60-70"); + tap_sounds << (f_p + "70-80"); + tap_sounds << (f_p + "80-90"); + tap_sounds << (f_p + "90-100"); + tap_sounds << (f_p + "100-110"); + tap_sounds << (f_p + "110-~"); } //------------------------------------------------------------------------------ diff --git a/addons/vl60/vl60k/src/vl60-step.cpp b/addons/vl60/vl60k/src/vl60-step.cpp index 8e868176..960a870d 100644 --- a/addons/vl60/vl60k/src/vl60-step.cpp +++ b/addons/vl60/vl60k/src/vl60-step.cpp @@ -21,37 +21,9 @@ void VL60k::stepTapSound() { double speed = abs(this->velocity) * 3.6; - QMap::const_iterator i = tap_sounds.constBegin(); - - QString soundPlay = ""; - - while (i != tap_sounds.constEnd()) - { - if (speed >= i.key()) - { - soundPlay = i.value(); - } - if (speed < i.key()) - { - break; - } - ++i; - } - - i = tap_sounds.constBegin(); - - int volume; - - while (i != tap_sounds.constEnd()) + for (int i = 0; i < tap_sounds.count(); ++i) { - if (soundPlay == i.value()) - { - volume = 100; - } else { - volume = 0; - } - emit soundSetVolume(i.value(), volume); - ++i; + emit volumeCurveStep(tap_sounds[i], static_cast(speed)); } } diff --git a/addons/vl60/vl60pk/include/vl60.h b/addons/vl60/vl60pk/include/vl60.h index 1798ff91..49dc9114 100644 --- a/addons/vl60/vl60pk/include/vl60.h +++ b/addons/vl60/vl60pk/include/vl60.h @@ -62,7 +62,7 @@ class VL60pk : public Vehicle }; /// Список звуков перестука - QMap tap_sounds; + QList tap_sounds; double U_bat; diff --git a/addons/vl60/vl60pk/src/vl60-init.cpp b/addons/vl60/vl60pk/src/vl60-init.cpp index 4989215f..b36c8398 100644 --- a/addons/vl60/vl60pk/src/vl60-init.cpp +++ b/addons/vl60/vl60pk/src/vl60-init.cpp @@ -212,18 +212,18 @@ void VL60pk::initTriggers() void VL60pk::initTapSounds() { QString f_p = "tap_"; - tap_sounds.insert(5, f_p + "5-10"); - tap_sounds.insert(10, f_p + "10-20"); - tap_sounds.insert(20, f_p + "20-30"); - tap_sounds.insert(30, f_p + "30-40"); - tap_sounds.insert(40, f_p + "40-50"); - tap_sounds.insert(50, f_p + "50-60"); - tap_sounds.insert(60, f_p + "60-70"); - tap_sounds.insert(70, f_p + "70-80"); - tap_sounds.insert(80, f_p + "80-90"); - tap_sounds.insert(90, f_p + "90-100"); - tap_sounds.insert(100, f_p + "100-110"); - tap_sounds.insert(110, f_p + "110-~"); + tap_sounds << (f_p + "5-10"); + tap_sounds << (f_p + "10-20"); + tap_sounds << (f_p + "20-30"); + tap_sounds << (f_p + "30-40"); + tap_sounds << (f_p + "40-50"); + tap_sounds << (f_p + "50-60"); + tap_sounds << (f_p + "60-70"); + tap_sounds << (f_p + "70-80"); + tap_sounds << (f_p + "80-90"); + tap_sounds << (f_p + "90-100"); + tap_sounds << (f_p + "100-110"); + tap_sounds << (f_p + "110-~"); } //------------------------------------------------------------------------------ diff --git a/addons/vl60/vl60pk/src/vl60-step.cpp b/addons/vl60/vl60pk/src/vl60-step.cpp index 6b76ee44..50e63561 100644 --- a/addons/vl60/vl60pk/src/vl60-step.cpp +++ b/addons/vl60/vl60pk/src/vl60-step.cpp @@ -21,37 +21,9 @@ void VL60pk::stepTapSound() { double speed = abs(this->velocity) * 3.6; - QMap::const_iterator i = tap_sounds.constBegin(); - - QString soundPlay = ""; - - while (i != tap_sounds.constEnd()) - { - if (speed >= i.key()) - { - soundPlay = i.value(); - } - if (speed < i.key()) - { - break; - } - ++i; - } - - i = tap_sounds.constBegin(); - - int volume; - - while (i != tap_sounds.constEnd()) + for (int i = 0; i < tap_sounds.count(); ++i) { - if (soundPlay == i.value()) - { - volume = 100; - } else { - volume = 0; - } - emit soundSetVolume(i.value(), volume); - ++i; + emit volumeCurveStep(tap_sounds[i], static_cast(speed)); } } diff --git a/simulator/sound-manager/include/sound-config.h b/simulator/sound-manager/include/sound-config.h index 734920e9..9bee4363 100644 --- a/simulator/sound-manager/include/sound-config.h +++ b/simulator/sound-manager/include/sound-config.h @@ -14,6 +14,7 @@ struct sound_config_t float init_pitch; bool loop; bool play_on_start; + QMap volume_curve; sound_config_t() : sound(Q_NULLPTR) diff --git a/simulator/sound-manager/include/sound-manager.h b/simulator/sound-manager/include/sound-manager.h index 9b9bf8f8..6f4b79ac 100644 --- a/simulator/sound-manager/include/sound-manager.h +++ b/simulator/sound-manager/include/sound-manager.h @@ -38,6 +38,8 @@ public slots: void setVolume(QString name, int volume); void setPitch(QString name, float pitch); + + void volumeCurveStep(QString name, float param); }; #endif // SOUND_MANAGER_H diff --git a/simulator/sound-manager/src/sound-manager.cpp b/simulator/sound-manager/src/sound-manager.cpp index 50e88fb2..db6ae07e 100644 --- a/simulator/sound-manager/src/sound-manager.cpp +++ b/simulator/sound-manager/src/sound-manager.cpp @@ -55,6 +55,16 @@ void SoundManager::loadSounds(const QString &vehicle_name) cfg.getBool(secNode, "Loop", sound_config.loop); cfg.getBool(secNode, "PlayOnStart", sound_config.play_on_start); + QString t_Str; + cfg.getString(secNode, "VolumeCurve", t_Str); + QRegExp rx("([+-]?\\d*\\.?\\d+)(?:\\t*)([+-]?\\d*\\.?\\d+)"); + foreach(const QString &lst1, t_Str.split(QLatin1Char('\n'))) + { + if (rx.indexIn(lst1) > -1) + sound_config.volume_curve.insert(rx.cap(1).toDouble(), + static_cast((rx.cap(2).toDouble()))); + } + sound_config.sound = new ASound(QString((soundsDir + fs.separator()).c_str()) + sound_config.path); @@ -155,3 +165,31 @@ void SoundManager::setPitch(QString name, float pitch) } } } + +//------------------------------------------------------------------------------ +// +//------------------------------------------------------------------------------ +void SoundManager::volumeCurveStep(QString name, float param) +{ + auto it = sounds.find(name); + + if (it.key() == name) + { + QMap::const_iterator i = it->volume_curve.constBegin(); + + int volume = 0; + + while (i != it->volume_curve.constEnd()) + { + if (param >= static_cast(i.key())) + { + volume = i.value(); + } else { + break; + } + ++i; + } + + it.value().sound->setVolume(volume); + } +} diff --git a/simulator/train/src/train.cpp b/simulator/train/src/train.cpp index 4f4d803e..5aeadc84 100644 --- a/simulator/train/src/train.cpp +++ b/simulator/train/src/train.cpp @@ -416,6 +416,7 @@ bool Train::loadTrain(QString cfg_path) connect(vehicle, &Vehicle::soundStop, soundMan, &SoundManager::stop, Qt::DirectConnection); connect(vehicle, &Vehicle::soundSetVolume, soundMan, &SoundManager::setVolume, Qt::DirectConnection); connect(vehicle, &Vehicle::soundSetPitch, soundMan, &SoundManager::setPitch, Qt::DirectConnection); + connect(vehicle, &Vehicle::volumeCurveStep, soundMan, &SoundManager::volumeCurveStep, Qt::DirectConnection); if (vehicles.size() !=0) { diff --git a/simulator/vehicle/include/vehicle.h b/simulator/vehicle/include/vehicle.h index 106b6152..7653ed63 100644 --- a/simulator/vehicle/include/vehicle.h +++ b/simulator/vehicle/include/vehicle.h @@ -183,6 +183,8 @@ public slots: void soundSetPitch(QString name, float pitch); + void volumeCurveStep(QString name, float param); + void sendFeedBackSignals(feedback_signals_t feedback_signals); protected: diff --git a/viewer/viewer/src/viewer.cpp b/viewer/viewer/src/viewer.cpp index 1741c570..0e8d6057 100644 --- a/viewer/viewer/src/viewer.cpp +++ b/viewer/viewer/src/viewer.cpp @@ -127,8 +127,6 @@ int RouteViewer::run() viewer.setCameraManipulator(cs.get()); - if (viewer.getCameraManipulator()->getName() == "cabine_view") - return viewer.run(); } From 06c4dfe0cb4770205bc3e2843c0a0eb3b12be844 Mon Sep 17 00:00:00 2001 From: Dima Govorukha Date: Sat, 14 Mar 2020 16:16:33 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=D0=97=D0=B2=D1=83=D0=BA=D0=B8=20254-=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BA=D1=80=D0=B0=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/vl60/vl60k/src/vl60-init.cpp | 3 ++ addons/vl60/vl60pk/src/vl60-debug.cpp | 5 ++- addons/vl60/vl60pk/src/vl60-init.cpp | 1 + simulator/device/include/loco-crane.h | 2 ++ simulator/device/src/loco-crane.cpp | 8 +++++ simulator/kvt254/include/kvt254.h | 8 +++++ simulator/kvt254/src/kvt254.cpp | 48 +++++++++++++++++++++++++++ 7 files changed, 72 insertions(+), 3 deletions(-) diff --git a/addons/vl60/vl60k/src/vl60-init.cpp b/addons/vl60/vl60k/src/vl60-init.cpp index 1869c325..ad28d605 100644 --- a/addons/vl60/vl60k/src/vl60-init.cpp +++ b/addons/vl60/vl60k/src/vl60-init.cpp @@ -96,6 +96,9 @@ void VL60k::initBrakeControls(QString modules_dir) loco_crane = loadLocoCrane(modules_dir + QDir::separator() + "kvt254"); loco_crane->read_config("kvt254"); + connect(loco_crane, &LocoCrane::soundPlay, this, &VL60k::soundPlay); + connect(loco_crane, &LocoCrane::soundStop, this, &VL60k::soundStop); + connect(loco_crane, &LocoCrane::soundSetVolume, this, &VL60k::soundSetVolume); } //------------------------------------------------------------------------------ diff --git a/addons/vl60/vl60pk/src/vl60-debug.cpp b/addons/vl60/vl60pk/src/vl60-debug.cpp index 94b95cb3..e2139716 100644 --- a/addons/vl60/vl60pk/src/vl60-debug.cpp +++ b/addons/vl60/vl60pk/src/vl60-debug.cpp @@ -5,7 +5,7 @@ //------------------------------------------------------------------------------ void VL60pk::debugPrint(double t) { - DebugMsg = QString("t: %1 x: %12 км v: %11 км/ч ЗР: %2 МПа ТЦ1: %3 ТЦ2: %4 Наж. на колодку: %5 кН Uву: %10 В Uтэд: %6 В Поз.: %7 Iя: %8 А Iв: %9 А 254pos: %13") + DebugMsg = QString("t: %1 x: %12 км v: %11 км/ч ЗР: %2 МПа ТЦ1: %3 ТЦ2: %4 Наж. на колодку: %5 кН Uву: %10 В Uтэд: %6 В Поз.: %7 Iя: %8 А Iв: %9 А") .arg(t, 10, 'f', 2) .arg(supply_reservoir->getPressure(), 4, 'f', 2) @@ -18,8 +18,7 @@ void VL60pk::debugPrint(double t) .arg(motor[TED1]->getIf(), 6,'f',1) .arg(vu[VU1]->getU_out(), 6, 'f', 1) .arg(velocity * Physics::kmh, 6, 'f', 1) - .arg(railway_coord / 1000.0, 7, 'f', 2) - .arg(loco_crane->getHandleShift()); + .arg(railway_coord / 1000.0, 7, 'f', 2); //DebugMsg = brake_crane->getDebugMsg(); } diff --git a/addons/vl60/vl60pk/src/vl60-init.cpp b/addons/vl60/vl60pk/src/vl60-init.cpp index b36c8398..3a92a719 100644 --- a/addons/vl60/vl60pk/src/vl60-init.cpp +++ b/addons/vl60/vl60pk/src/vl60-init.cpp @@ -98,6 +98,7 @@ void VL60pk::initBrakeControls(QString modules_dir) loco_crane = loadLocoCrane(modules_dir + QDir::separator() + "kvt254"); loco_crane->read_config("kvt254"); connect(loco_crane, &LocoCrane::soundPlay, this, &VL60pk::soundPlay); + connect(loco_crane, &LocoCrane::soundStop, this, &VL60pk::soundStop); connect(loco_crane, &LocoCrane::soundSetVolume, this, &VL60pk::soundSetVolume); } diff --git a/simulator/device/include/loco-crane.h b/simulator/device/include/loco-crane.h index 6c906b8e..34ea067c 100644 --- a/simulator/device/include/loco-crane.h +++ b/simulator/device/include/loco-crane.h @@ -30,6 +30,8 @@ class DEVICE_EXPORT LocoCrane : public BrakeDevice virtual double getAirDistribPressure() const; + virtual void stepSound(); + void release(bool is_release); protected: diff --git a/simulator/device/src/loco-crane.cpp b/simulator/device/src/loco-crane.cpp index 72c65eb5..1ed89e7b 100644 --- a/simulator/device/src/loco-crane.cpp +++ b/simulator/device/src/loco-crane.cpp @@ -80,6 +80,14 @@ void LocoCrane::release(bool is_release) this->is_release = static_cast(is_release); } +//------------------------------------------------------------------------------ +// +//------------------------------------------------------------------------------ +void LocoCrane::stepSound() +{ + return; +} + //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ diff --git a/simulator/kvt254/include/kvt254.h b/simulator/kvt254/include/kvt254.h index 7bc294ff..02e579d1 100644 --- a/simulator/kvt254/include/kvt254.h +++ b/simulator/kvt254/include/kvt254.h @@ -53,6 +53,10 @@ class LocoCrane254 : public LocoCrane double pos_duration; + double volume; + + double p_volume; + int dir; int pos_num; @@ -65,11 +69,15 @@ class LocoCrane254 : public LocoCrane std::array k; + bool isStop; + void ode_system(const state_vector_t &Y, state_vector_t &dYdt, double t); void load_config(CfgReader &cfg); void stepKeysControl(double t, double dt); + + void stepSound(); }; #endif // KVT254_H diff --git a/simulator/kvt254/src/kvt254.cpp b/simulator/kvt254/src/kvt254.cpp index 4a79fd2d..528ff3fa 100644 --- a/simulator/kvt254/src/kvt254.cpp +++ b/simulator/kvt254/src/kvt254.cpp @@ -17,6 +17,7 @@ LocoCrane254::LocoCrane254(QObject *parent) : LocoCrane(parent) , dir(0) , positions({0.0, 0.325, 0.5, 0.752, 1.0}) , step_pressures({0.0, 0.13, 0.20, 0.30, 0.40}) + , isStop(false) { std::fill(K.begin(), K.end(), 0.0); std::fill(k.begin(), k.end(), 0.0); @@ -117,6 +118,53 @@ void LocoCrane254::ode_system(const state_vector_t &Y, dYdt[1] = Q2 / V2; // p2 dYdt[2] = Qpz / Vpz; // p_pz + + stepSound(); +} + +//------------------------------------------------------------------------------ +// +//------------------------------------------------------------------------------ +void LocoCrane254::stepSound() +{ + p_volume = volume; + + // 250000 поправочный коэффициент для перевода 1кг/cм^3 в 1кг/м^3 + // Для звуков взято 400000 с малым запасом + volume = abs(Qbc) * 400000; + + if (volume > 30) + { + if (Qbc > 0) + { + if (p_volume <= 30) + { + emit soundPlay("254_vpusk"); + } + emit soundSetVolume("254_vypusk", 0); + emit soundSetVolume("254_vpusk", volume); + } + + if (Qbc < 0) + { + if (p_volume <= 30) + { + emit soundPlay("254_vypusk"); + } + emit soundSetVolume("254_vpusk", 0); + emit soundSetVolume("254_vypusk", volume); + } + isStop = false; + } + else + { + if (!isStop) + { + emit soundStop("254_vpusk"); + emit soundStop("254_vypusk"); + isStop = true; + } + } } //------------------------------------------------------------------------------ From 48d3b9fc567e5533641e17227dfd9a139201e150 Mon Sep 17 00:00:00 2001 From: Dima Govorukha Date: Sat, 14 Mar 2020 19:45:14 +0200 Subject: [PATCH 3/3] =?UTF-8?q?=D0=97=D0=B2=D1=83=D0=BA=D0=B8=20=D0=AD?= =?UTF-8?q?=D0=9A=D0=93-8=D0=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/vl60/vl60-equipment/include/ekg-8g.h | 3 +++ addons/vl60/vl60-equipment/src/ekg-8g.cpp | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/addons/vl60/vl60-equipment/include/ekg-8g.h b/addons/vl60/vl60-equipment/include/ekg-8g.h index 3478896d..c6d38687 100644 --- a/addons/vl60/vl60-equipment/include/ekg-8g.h +++ b/addons/vl60/vl60-equipment/include/ekg-8g.h @@ -65,6 +65,9 @@ class EKG_8G : public Device bool is_auto; + /// Имя звука ЭКГ-8Ж + QString sound_name; + /// Таймер управления переключением позиций Timer pos_switcher; diff --git a/addons/vl60/vl60-equipment/src/ekg-8g.cpp b/addons/vl60/vl60-equipment/src/ekg-8g.cpp index 4151c843..21f779b4 100644 --- a/addons/vl60/vl60-equipment/src/ekg-8g.cpp +++ b/addons/vl60/vl60-equipment/src/ekg-8g.cpp @@ -14,6 +14,7 @@ EKG_8G::EKG_8G(QObject *parent) : Device(parent) , is_fix_off(false) , dir(0) , is_auto(false) + , sound_name("") { connect(&pos_switcher, &Timer::process, this, &EKG_8G::slotPosSwitch); @@ -99,6 +100,7 @@ void EKG_8G::process() // Нулевая позиция if (km_state.pos_state[POS_ZERO] && (position != 0) && !is_auto) { + sound_name = "EKG_serv_auto"; pos_switcher.start(); dir = -1; } @@ -106,6 +108,7 @@ void EKG_8G::process() // Фиксация пуска if (km_state.pos_state[POS_FP]) { + sound_name = ""; is_fix_start = true; dir = 1; } @@ -113,6 +116,7 @@ void EKG_8G::process() // Ручной пуск if (km_state.pos_state[POS_RP] && is_fix_start) { + sound_name = "EKG_serv_rp"; is_fix_start = false; pos_switcher.start(); } @@ -120,6 +124,7 @@ void EKG_8G::process() // Фиксация выключения if (km_state.pos_state[POS_FV]) { + sound_name = ""; is_fix_off = true; dir = -1; } @@ -127,6 +132,7 @@ void EKG_8G::process() // Ручное выключение if (km_state.pos_state[POS_RV] && is_fix_off) { + sound_name = "EKG_serv_rp"; is_fix_off = false; pos_switcher.start(); } @@ -134,6 +140,7 @@ void EKG_8G::process() // Автоматический пуск if (km_state.pos_state[POS_AP] && !is_auto) { + sound_name = "EKG_serv_auto"; pos_switcher.start(); dir = 1; } @@ -141,6 +148,7 @@ void EKG_8G::process() // Автоматический пуск if (km_state.pos_state[POS_AV] && !is_auto) { + sound_name = "EKG_serv_auto"; pos_switcher.start(); dir = -1; } @@ -219,7 +227,7 @@ void EKG_8G::slotPosSwitch() position = cut(position, 0, static_cast(NUM_POSITIONS - 1)); if ( (position != 0) && (position != NUM_POSITIONS - 1) ) - emit soundPlay("EKG_serv"); + emit soundPlay(sound_name); // Останавливаемся, если не находимся на переходных позициях if ( ( (position < PP_MIN) || (position > PP_MAX) ) && !is_auto )