add MML tones

This commit is contained in:
my 2026-09-15 15:20:29 +02:00
parent ac544c1790
commit 8b03bc5e84
8 changed files with 72 additions and 28 deletions

View file

@ -1,10 +1,8 @@
#nick=your nick, picked randomly on first run
brightness=200
msg_freq=1800
msg_ms=20
sys_freq=440
sys_ms=10
tones_msg=T300 O4 l8 D l4 A+
tones_sys=T300 O4 l8 A l4 D+
touch_threshold=300

View file

@ -18,16 +18,21 @@ board_build.filesystem = littlefs
monitor_speed = 115200
upload_speed = 921600
;monitor_filters = send_on_enter
build_src_filter = +<meshberry/> -<chat-relay/>
build_src_filter =
+<meshberry/>
-<chat-relay/>
lib_deps =
lovyan03/LovyanGFX @ ^1.2
lvgl/lvgl @ ^9.0
; t-vk/ESP32 BLE Keyboard@^0.3.2
https://github.com/sakul-the-one/sakuls-ESP32-BLE-Keyboard
h2zero/NimBLE-Arduino
https://github.com/maxint-rd/MmlMusic
build_flags =
-DLV_CONF_INCLUDE_SIMPLE
-I include
; use strchr instead of strchr_P
-Dstrchr_P=strchr
; We only need HID peripheral from NimBLE
; saving some memory here.
-DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
@ -39,7 +44,9 @@ board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
build_src_filter = -<meshberry/> +<chat-relay/> ; ignores root
build_src_filter =
-<meshberry/>
+<chat-relay/> ; ignores meshberry
lib_deps =
build_flags =
-I include

View file

@ -403,8 +403,14 @@ void handleCommand(const char* in) {
ui_push_message("", "Usage: /set color_bg ff0000", false, true);
} else {
*sp = '\0';
if (settings_set_color(args, sp + 1))
size_t klen = strlen(args);
bool is_tones = klen > 6 && !strcmp(args + klen - 6, "_tones");
bool ok = is_tones ? settings_set_tones(args, sp + 1)
: settings_set_color(args, sp + 1);
if (ok)
ui_push_message("", "Saved. Restart to apply.", false, true);
else if (is_tones)
ui_push_message("", "Unknown tones key.", false, true);
else
ui_push_message("", "Unknown color or bad hex value.", false, true);
}
@ -435,7 +441,7 @@ void handleCommand(const char* in) {
ui_push_message("", "/bt : toggle BT send mode", false, true);
ui_push_message("", "/set color_bg ff0000 : set a color (restart to apply)", false, true);
ui_push_message("", "/people : list connected", false, true);
ui_push_message("", "/sleep : sleep device", false, true);
ui_push_message("", "/sleep or /s : sleep device", false, true);
ui_push_message("", "TAB : notes mode", false, true);
//drawChatWindow();

View file

@ -45,5 +45,6 @@ void loop() {
char key = Serial.available() ? (char)Serial.read() : cardkb_read();
chat_tick(key); // TODO: debug why a serial key does not show in the UI?
ui_tick();
sound_tick();
delay(5);
}

View file

@ -1,16 +1,15 @@
#include "settings.h"
#include <Arduino.h>
#include <LittleFS.h>
#include <string>
settings_t g_settings;
static const settings_t DEFAULTS = {
.nick = NICK_DEFAULT_PREFIX,
.brightness = 200,
.msg_freq = 1800,
.msg_ms = 20,
.sys_freq = 440,
.sys_ms = 10,
.tones_msg = "T140 G",
.tones_sys = "T140 A",
.touch_threshold = TOUCH_THRESHOLD,
.color_bg = {.blue = 0x11, .green = 0x11, .red = 0x11},
.color_header_bg = {.blue = 0x1e, .green = 0x1e, .red = 0x1e},
@ -43,10 +42,8 @@ static bool is_hex6(const char* s) {
static bool apply_kv(const char* key, const char* val) {
if (!strcmp(key, "nick")) { strncpy(g_settings.nick, val, CHAT_MAX_NICK_LEN - 1); }
else if (!strcmp(key, "brightness")) { g_settings.brightness = (uint8_t)constrain(atoi(val), 0, 255); }
else if (!strcmp(key, "msg_freq")) { g_settings.msg_freq = (uint16_t)atoi(val); }
else if (!strcmp(key, "msg_ms")) { g_settings.msg_ms = (uint16_t)atoi(val); }
else if (!strcmp(key, "sys_freq")) { g_settings.sys_freq = (uint16_t)atoi(val); }
else if (!strcmp(key, "sys_ms")) { g_settings.sys_ms = (uint16_t)atoi(val); }
else if (!strcmp(key, "tones_msg")) { g_settings.tones_msg = String(val); }
else if (!strcmp(key, "tones_sys")) { g_settings.tones_sys = String(val); }
else if (!strcmp(key, "touch_threshold")) { g_settings.touch_threshold = (uint16_t)atoi(val); }
else if (!strcmp(key, "color_bg")) { if (!is_hex6(val)) return false; g_settings.color_bg = parse_color(val); }
else if (!strcmp(key, "color_header_bg")) { if (!is_hex6(val)) return false; g_settings.color_header_bg = parse_color(val); }
@ -60,12 +57,12 @@ static bool apply_kv(const char* key, const char* val) {
}
static void dump_settings() {
Serial.println("[settings] ---- effective config ----");
Serial.println("[settings]");
Serial.printf ("[settings] nick=%s brightness=%d\n",
g_settings.nick, g_settings.brightness);
Serial.printf ("[settings] msg_freq=%u msg_ms=%u sys_freq=%u sys_ms=%u touch_threshold=%u\n",
g_settings.msg_freq, g_settings.msg_ms, g_settings.sys_freq,
g_settings.sys_ms, g_settings.touch_threshold);
Serial.printf ("[settings] tones_msg=%s tones_sys=%s\n",
g_settings.tones_msg.c_str(), g_settings.tones_sys.c_str());
Serial.printf ("[settings] touch_threshold=%u\n", g_settings.touch_threshold);
Serial.printf ("[settings] color_bg=%02x%02x%02x color_header_bg=%02x%02x%02x\n",
g_settings.color_bg.red, g_settings.color_bg.green, g_settings.color_bg.blue,
g_settings.color_header_bg.red, g_settings.color_header_bg.green, g_settings.color_header_bg.blue);
@ -76,7 +73,7 @@ static void dump_settings() {
Serial.printf ("[settings] color_system=%02x%02x%02x color_input_prompt=%02x%02x%02x\n",
g_settings.color_system.red, g_settings.color_system.green, g_settings.color_system.blue,
g_settings.color_input_prompt.red, g_settings.color_input_prompt.green, g_settings.color_input_prompt.blue);
Serial.println("[settings] ----------------------------");
Serial.println("[settings]");
}
// Public
@ -170,3 +167,13 @@ bool settings_set_color(const char* key, const char* hex) {
rewrite_config_line(key, hex);
return true;
}
bool settings_set_tones(const char* key, const char* tones) {
if (strlen(key) <= 6 || strcmp(key + strlen(key) - 6, "_tones") != 0) {
return false;
}
if (!apply_kv(key, tones)) return false; // unknown key or bad tones
rewrite_config_line(key, tones);
return true;
}

View file

@ -1,16 +1,15 @@
#pragma once
#include <lvgl.h>
#include "config.h"
#include <Arduino.h>
// All values read from /config.txt on LittleFS.
struct settings_t {
char nick[CHAT_MAX_NICK_LEN];
uint8_t brightness;
uint16_t msg_freq; // Hz, notification beep for incoming messages
uint16_t msg_ms; // duration in ms
uint16_t sys_freq; // Hz, beep for join / leave events
uint16_t sys_ms; // duration in ms
uint16_t touch_threshold; // touch7 (GPIO27) wake-from-sleep sensitivity
String tones_msg; // MML string for incoming message
String tones_sys; // MML string for system message
uint16_t touch_threshold; // touch7 (GPIO27) wake-from-sleep sensitivity
lv_color_t color_bg;
lv_color_t color_header_bg;
lv_color_t color_msg;
@ -26,3 +25,4 @@ extern settings_t g_settings;
void settings_load();
void settings_set_nick(const char* nick);
bool settings_set_color(const char* key, const char* hex);
bool settings_set_tones(const char* key, const char* tones);

View file

@ -2,11 +2,35 @@
#include "config.h"
#include "settings.h"
#include <Arduino.h>
#include <MmlMusic.h>
MmlMusic music;
static bool sound_tone_callback(unsigned int frequency, unsigned long length, uint8_t nTrack, uint8_t nVolume) {
if (frequency > 0) {
tone(PIN_SPEAKER, frequency);
} else if (length == 0) {
noTone(PIN_SPEAKER);
}
return true;
}
void sound_init() {
pinMode(PIN_SPEAKER_EN, OUTPUT);
digitalWrite(PIN_SPEAKER_EN, LOW); // LOW = amp enabled
music.setToneCallback(sound_tone_callback);
}
void sound_msg_in() { tone(PIN_SPEAKER, g_settings.msg_freq, g_settings.msg_ms); }
void sound_system() { tone(PIN_SPEAKER, g_settings.sys_freq, g_settings.sys_ms); }
void sound_tick() {
music.continuePlaying();
}
void sound_msg_in() {
//tone(PIN_SPEAKER, g_settings.snd_msg_freq, g_settings.snd_msg_ms);
//music.play("T140 O5 O5 D L4 G L8 D G L4 B. G8 G. F#8 G. G#8 A2");
music.play(g_settings.tones_msg.c_str());
}
void sound_system() {
// tone(PIN_SPEAKER, g_settings.snd_sys_freq, g_settings.snd_sys_ms);
music.play(g_settings.tones_sys.c_str());
}

View file

@ -1,5 +1,6 @@
#pragma once
void sound_init();
void sound_tick(); // call regularly from loop() to advance MML playback
void sound_msg_in(); // short high beep, new chat message
void sound_system(); // short low beep , join / leave