Settings - Sound: Allow to set items to None

This commit is contained in:
vanous
2026-06-07 09:13:02 +02:00
parent 484d8cb093
commit 7703b3ae36
6 changed files with 28 additions and 21 deletions

View File

@@ -37,9 +37,9 @@ Press **Cancel/Back** to save and return to the home screen.
| -------------- | ------------------------------ | ------------------------------------------------------------ | | -------------- | ------------------------------ | ------------------------------------------------------------ |
| Buzzer | On / Off / Auto | Auto: silences while BLE connected, re-enables on disconnect | | Buzzer | On / Off / Auto | Auto: silences while BLE connected, re-enables on disconnect |
| Volume | 15 | LEFT/RIGHT; preview tone plays on each change | | Volume | 15 | LEFT/RIGHT; preview tone plays on each change |
| DM Melody | built-in / Melody 1 / Melody 2 | Notification sound for incoming private messages | | DM Melody | built-in / Melody 1 / Melody 2 / None | Notification sound for incoming private messages. `None` disables the sound for this event. |
| Channel Melody | built-in / Melody 1 / Melody 2 | Notification sound for incoming channel messages | | Channel Melody | built-in / Melody 1 / Melody 2 / None | Notification sound for incoming channel messages. `None` disables the sound for this event. |
| AD sound | built-in / Melody 1 / Melody 2 | Sound played whenever an **advert** is received from *any* node — pairs with Auto-Advert as an audible "in range" heartbeat (see Tools Auto-Advert). There's no *off* here; `built-in` still chirps, so silence it via the **Buzzer** setting | | AD sound | built-in / Melody 1 / Melody 2 / None | Sound played whenever an **advert** is received from *any* node — pairs with Auto-Advert as an audible "in range" heartbeat (see Tools Auto-Advert). `None` disables the sound for this event. |
Melody 1 and Melody 2 are custom sequences editable in **Tools Ringtone Editor**. Melody 1 and Melody 2 are custom sequences editable in **Tools Ringtone Editor**.

View File

@@ -159,7 +159,7 @@ Saved **waypoints are included** in the export as GPX `<wpt>` elements (with the
Periodically broadcasts a 0-hop advert with your GPS position. Configurable interval: off / 30 s / 1 min / 2 min / 5 min / 10 min / 30 min / 1 h. A blinking **A** appears in the status bar while active. Periodically broadcasts a 0-hop advert with your GPS position. Configurable interval: off / 30 s / 1 min / 2 min / 5 min / 10 min / 30 min / 1 h. A blinking **A** appears in the status bar while active.
> [!TIP] > [!TIP]
> **Audible connection heartbeat** — the device chirps each time it *receives* an advert from any node (sound chosen in **Settings Sound AD sound**). With Auto-Advert running on both ends (e.g. two people on a hike), each hearing the other's periodic advert becomes a hands-free "in range" beep — no need to look at the screen. It fires for **every** received advert, so in a busy mesh it can get chatty; to silence it set **Settings Sound Buzzer** to *Off* (or *Auto*, which mutes while a companion app is connected) — `built-in` still chirps. > **Audible connection heartbeat** — the device chirps each time it *receives* an advert from any node (sound chosen in **Settings Sound AD sound**). With Auto-Advert running on both ends (e.g. two people on a hike), each hearing the other's periodic advert becomes a hands-free "in range" beep — no need to look at the screen. It fires for **every** received advert, so in a busy mesh it can get chatty; choose `None` in **Settings Sound AD sound** to silence just this event, or set **Settings Sound Buzzer** to *Off* (or *Auto*, which mutes while a companion app is connected) to silence all buzzer output.
--- ---

View File

@@ -322,7 +322,8 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
rd(&_prefs.trail_show_pace, sizeof(_prefs.trail_show_pace)); rd(&_prefs.trail_show_pace, sizeof(_prefs.trail_show_pace));
// These three were appended together; an older file leaves stray bytes here // These three were appended together; an older file leaves stray bytes here
// (the old tail sentinel gets partly consumed), so clamp out-of-range values. // (the old tail sentinel gets partly consumed), so clamp out-of-range values.
if (_prefs.notif_melody_ad > 2) _prefs.notif_melody_ad = 0; // Values: 0=built-in, 1=melody1, 2=melody2, 3=none.
if (_prefs.notif_melody_ad > 3) _prefs.notif_melody_ad = 0;
if (_prefs.units_imperial > 1) _prefs.units_imperial = 0; if (_prefs.units_imperial > 1) _prefs.units_imperial = 0;
if (_prefs.trail_show_pace > 1) _prefs.trail_show_pace = 0; if (_prefs.trail_show_pace > 1) _prefs.trail_show_pace = 0;

View File

@@ -69,7 +69,7 @@ struct NodePrefs { // persisted to file
uint8_t ringtone2_bpm_idx; uint8_t ringtone2_bpm_idx;
uint8_t ringtone2_len; uint8_t ringtone2_len;
uint8_t ringtone2_notes[32]; uint8_t ringtone2_notes[32];
// Global melodies for notifications: 0=built-in, 1=melody1, 2=melody2 // Global melodies for notifications: 0=built-in, 1=melody1, 2=melody2, 3=none
uint8_t notif_melody_dm; uint8_t notif_melody_dm;
uint8_t notif_melody_ch; uint8_t notif_melody_ch;
uint8_t notif_melody_ad; uint8_t notif_melody_ad;

View File

@@ -89,6 +89,8 @@ class SettingsScreen : public UIScreen {
static const int LOW_BAT_COUNT = 7; static const int LOW_BAT_COUNT = 7;
static const char* BATT_DISPLAY_LABELS[3]; static const char* BATT_DISPLAY_LABELS[3];
static const int BATT_DISPLAY_COUNT = 3; static const int BATT_DISPLAY_COUNT = 3;
static const char* SOUND_LABELS[4];
static const int SOUND_COUNT = 4;
#if FEAT_FULL_REFRESH_SETTING #if FEAT_FULL_REFRESH_SETTING
static const char* EINK_FULL_REFRESH_LABELS[5]; static const char* EINK_FULL_REFRESH_LABELS[5];
static const int EINK_FULL_REFRESH_COUNT = 5; static const int EINK_FULL_REFRESH_COUNT = 5;
@@ -438,21 +440,18 @@ class SettingsScreen : public UIScreen {
} else if (item == DM_MELODY) { } else if (item == DM_MELODY) {
display.print("DM sound"); display.print("DM sound");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
{ static const char* L[] = { "built-in", "M1", "M2" }; { uint8_t v = p ? p->notif_melody_dm : 0;
uint8_t v = p ? p->notif_melody_dm : 0; display.print(SOUND_LABELS[v < SOUND_COUNT ? v : 0]); }
display.print(L[v < 3 ? v : 0]); }
} else if (item == CH_MELODY) { } else if (item == CH_MELODY) {
display.print("Ch sound"); display.print("Ch sound");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
{ static const char* L[] = { "built-in", "M1", "M2" }; { uint8_t v = p ? p->notif_melody_ch : 0;
uint8_t v = p ? p->notif_melody_ch : 0; display.print(SOUND_LABELS[v < SOUND_COUNT ? v : 0]); }
display.print(L[v < 3 ? v : 0]); }
} else if (item == AD_SOUND) { } else if (item == AD_SOUND) {
display.print("AD sound"); display.print("AD sound");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
{ static const char* L[] = { "built-in", "M1", "M2" }; { uint8_t v = p ? p->notif_melody_ad : 0;
uint8_t v = p ? p->notif_melody_ad : 0; display.print(SOUND_LABELS[v < SOUND_COUNT ? v : 0]); }
display.print(L[v < 3 ? v : 0]); }
} else if (isHomePage(item)) { } else if (isHomePage(item)) {
if (p) ensurePageOrderInit(p); if (p) ensurePageOrderInit(p);
int pos = homePagePosition(item, p); int pos = homePagePosition(item, p);
@@ -696,15 +695,15 @@ public:
return right || left; return right || left;
} }
if (_selected == DM_MELODY && p && (left || right || enter)) { if (_selected == DM_MELODY && p && (left || right || enter)) {
p->notif_melody_dm = (p->notif_melody_dm + (left ? 2 : 1)) % 3; p->notif_melody_dm = (p->notif_melody_dm + (left ? SOUND_COUNT - 1 : 1)) % SOUND_COUNT;
_dirty = true; return true; _dirty = true; return true;
} }
if (_selected == CH_MELODY && p && (left || right || enter)) { if (_selected == CH_MELODY && p && (left || right || enter)) {
p->notif_melody_ch = (p->notif_melody_ch + (left ? 2 : 1)) % 3; p->notif_melody_ch = (p->notif_melody_ch + (left ? SOUND_COUNT - 1 : 1)) % SOUND_COUNT;
_dirty = true; return true; _dirty = true; return true;
} }
if (_selected == AD_SOUND && p && (left || right || enter)) { if (_selected == AD_SOUND && p && (left || right || enter)) {
p->notif_melody_ad = (p->notif_melody_ad + (left ? 2 : 1)) % 3; p->notif_melody_ad = (p->notif_melody_ad + (left ? SOUND_COUNT - 1 : 1)) % SOUND_COUNT;
_dirty = true; return true; _dirty = true; return true;
} }
if (isHomePage(_selected) && p) { if (isHomePage(_selected) && p) {
@@ -839,6 +838,7 @@ const char* SettingsScreen::AUTO_OFF_LABELS[5] = { "5s", "15s", "30s", "60s"
const uint16_t SettingsScreen::LOW_BAT_OPTS[7] = { 0, 3000, 3100, 3200, 3300, 3400, 3500 }; const uint16_t SettingsScreen::LOW_BAT_OPTS[7] = { 0, 3000, 3100, 3200, 3300, 3400, 3500 };
const char* SettingsScreen::LOW_BAT_LABELS[7] = { "off", "3.0V", "3.1V", "3.2V", "3.3V", "3.4V", "3.5V" }; const char* SettingsScreen::LOW_BAT_LABELS[7] = { "off", "3.0V", "3.1V", "3.2V", "3.3V", "3.4V", "3.5V" };
const char* SettingsScreen::BATT_DISPLAY_LABELS[3] = { "icon", "%", "V" }; const char* SettingsScreen::BATT_DISPLAY_LABELS[3] = { "icon", "%", "V" };
const char* SettingsScreen::SOUND_LABELS[4] = { "built-in", "M1", "M2", "None" };
#if FEAT_FULL_REFRESH_SETTING #if FEAT_FULL_REFRESH_SETTING
const char* SettingsScreen::EINK_FULL_REFRESH_LABELS[5] = { "off", "5", "10", "20", "30" }; const char* SettingsScreen::EINK_FULL_REFRESH_LABELS[5] = { "off", "5", "10", "20", "30" };
#endif #endif

View File

@@ -1413,7 +1413,9 @@ switch(t){
{ slot = _node_prefs->dm_melody[i].slot; break; } { slot = _node_prefs->dm_melody[i].slot; break; }
} }
bool custom_played = false; bool custom_played = false;
if (slot > 0 && _node_prefs) { if (slot == 3) {
custom_played = true; // explicit silence
} else if (slot > 0 && _node_prefs) {
if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf
buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf)); buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf));
if (_notif_mel_buf[0]) { if (_notif_mel_buf[0]) {
@@ -1449,7 +1451,9 @@ switch(t){
slot = (_node_prefs->ch_notif_melody_2 & mask) ? 2 : 1; slot = (_node_prefs->ch_notif_melody_2 & mask) ? 2 : 1;
} }
bool custom_played = false; bool custom_played = false;
if (slot > 0 && _node_prefs) { if (slot == 3) {
custom_played = true; // explicit silence
} else if (slot > 0 && _node_prefs) {
if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf
buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf)); buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf));
if (_notif_mel_buf[0]) { if (_notif_mel_buf[0]) {
@@ -1469,7 +1473,9 @@ switch(t){
if (!buzzer.isQuiet()) { if (!buzzer.isQuiet()) {
int slot = _node_prefs ? (int)_node_prefs->notif_melody_ad : 0; int slot = _node_prefs ? (int)_node_prefs->notif_melody_ad : 0;
bool custom_played = false; bool custom_played = false;
if (slot > 0 && _node_prefs) { if (slot == 3) {
custom_played = true; // explicit silence
} else if (slot > 0 && _node_prefs) {
if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf
buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf)); buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf));
if (_notif_mel_buf[0]) { if (_notif_mel_buf[0]) {