Scrolling text #DATETIME bugfix.

Cosmetic changes.
This commit is contained in:
Blaz Kristan 2022-06-16 21:52:14 +02:00
parent cf54115077
commit f3364e1327
2 changed files with 89 additions and 59 deletions

View File

@ -144,7 +144,8 @@ float fftAdd(int from, int to) {
} }
// FFT main code // FFT main code
void FFTcode(void * parameter) { void FFTcode(void * parameter)
{
DEBUGSR_PRINT("FFT running on core: "); DEBUGSR_PRINTLN(xPortGetCoreID()); DEBUGSR_PRINT("FFT running on core: "); DEBUGSR_PRINTLN(xPortGetCoreID());
#ifdef MAJORPEAK_SUPPRESS_NOISE #ifdef MAJORPEAK_SUPPRESS_NOISE
static double xtemp[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; static double xtemp[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@ -367,7 +368,6 @@ class AudioReactive : public Usermod {
int8_t mclkPin = MLCK_PIN; int8_t mclkPin = MLCK_PIN;
#endif #endif
#define UDP_SYNC_HEADER "00001"
struct audioSyncPacket { struct audioSyncPacket {
char header[6]; char header[6];
uint8_t myVals[32]; // 32 Bytes uint8_t myVals[32]; // 32 Bytes
@ -416,20 +416,21 @@ class AudioReactive : public Usermod {
bool agcEffect = false; bool agcEffect = false;
int last_soundAgc = -1; int last_soundAgc = -1;
float control_integrated = 0.0f; // "integrator control" = accumulated error float control_integrated = 0.0f; // "integrator control" = accumulated error
unsigned long last_update_time = 0;
unsigned long last_kick_time = 0;
uint8_t last_user_inputLevel = 0;
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
static const char _name[]; static const char _name[];
static const char _enabled[];
static const char _analogmic[]; static const char _analogmic[];
static const char _digitalmic[]; static const char _digitalmic[];
static const char UDP_SYNC_HEADER[];
// private methods // private methods
bool isValidUdpSyncVersion(const char *header) { void logAudio()
return strncmp(header, UDP_SYNC_HEADER, 6) == 0; {
}
void logAudio() {
#ifdef MIC_LOGGER #ifdef MIC_LOGGER
//Serial.print("micData:"); Serial.print(micData); Serial.print("\t"); //Serial.print("micData:"); Serial.print(micData); Serial.print("\t");
//Serial.print("micDataSm:"); Serial.print(micDataSm); Serial.print("\t"); //Serial.print("micDataSm:"); Serial.print(micDataSm); Serial.print("\t");
@ -522,7 +523,8 @@ class AudioReactive : public Usermod {
* a) normal zone - very slow adjustment * a) normal zone - very slow adjustment
* b) emergency zome (<10% or >90%) - very fast adjustment * b) emergency zome (<10% or >90%) - very fast adjustment
*/ */
void agcAvg() { void agcAvg()
{
const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function
float lastMultAgc = multAgc; // last muliplier used float lastMultAgc = multAgc; // last muliplier used
@ -605,9 +607,8 @@ class AudioReactive : public Usermod {
} // agcAvg() } // agcAvg()
void getSample() { void getSample()
static long peakTime; {
const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function
#ifdef WLED_DISABLE_SOUND #ifdef WLED_DISABLE_SOUND
@ -677,24 +678,24 @@ class AudioReactive : public Usermod {
if (userVar1 == 0) samplePeak = 0; if (userVar1 == 0) samplePeak = 0;
// Poor man's beat detection by seeing if sample > Average + some value. // Poor man's beat detection by seeing if sample > Average + some value.
// Serial.print(binNum); Serial.print("\t"); Serial.print(fftBin[binNum]); Serial.print("\t"); Serial.print(fftAvg[binNum/16]); Serial.print("\t"); Serial.print(maxVol); Serial.print("\t"); Serial.println(samplePeak); // Serial.print(binNum); Serial.print("\t"); Serial.print(fftBin[binNum]); Serial.print("\t"); Serial.print(fftAvg[binNum/16]); Serial.print("\t"); Serial.print(maxVol); Serial.print("\t"); Serial.println(samplePeak);
if ((fftBin[binNum] > maxVol) && (millis() > (peakTime + 100))) { // This goe through ALL of the 255 bins if ((fftBin[binNum] > maxVol) && (millis() > (timeOfPeak + 100))) { // This goe through ALL of the 255 bins
// if (sample > (sampleAvg + maxVol) && millis() > (peakTime + 200)) { // if (sample > (sampleAvg + maxVol) && millis() > (timeOfPeak + 200)) {
// Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync. // Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync.
samplePeak = 1; samplePeak = 1;
timeOfPeak = millis(); timeOfPeak = millis();
udpSamplePeak = 1; udpSamplePeak = 1;
userVar1 = samplePeak; userVar1 = samplePeak;
peakTime=millis();
} }
} // getSample() } // getSample()
void transmitAudioData() { void transmitAudioData()
{
if (!udpSyncConnected) return; if (!udpSyncConnected) return;
//DEBUGSR_PRINTLN("Transmitting UDP Mic Packet"); //DEBUGSR_PRINTLN("Transmitting UDP Mic Packet");
audioSyncPacket transmitData; audioSyncPacket transmitData;
strncpy(transmitData.header, UDP_SYNC_HEADER, 6); strncpy_P(transmitData.header, PSTR(UDP_SYNC_HEADER), 6);
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
transmitData.myVals[i] = myVals[i]; transmitData.myVals[i] = myVals[i];
@ -720,7 +721,13 @@ class AudioReactive : public Usermod {
} // transmitAudioData() } // transmitAudioData()
void receiveAudioData() { bool isValidUdpSyncVersion(const char *header) {
return strncmp_P(header, PSTR(UDP_SYNC_HEADER), 6) == 0;
}
void receiveAudioData()
{
if (!udpSyncConnected) return; if (!udpSyncConnected) return;
//DEBUGSR_PRINTLN("Checking for UDP Microphone Packet"); //DEBUGSR_PRINTLN("Checking for UDP Microphone Packet");
@ -764,8 +771,8 @@ class AudioReactive : public Usermod {
* You can use it to initialize variables, sensors or similar. * You can use it to initialize variables, sensors or similar.
* It is called *AFTER* readFromConfig() * It is called *AFTER* readFromConfig()
*/ */
void setup() { void setup()
{
if (!initDone) { if (!initDone) {
// usermod exchangeable data // usermod exchangeable data
// we will assign all usermod exportable data here as pointers to original variables or arrays and allocate memory for pointers // we will assign all usermod exportable data here as pointers to original variables or arrays and allocate memory for pointers
@ -859,6 +866,7 @@ class AudioReactive : public Usermod {
} }
delay(250); // give mictophone enough time to initialise delay(250); // give mictophone enough time to initialise
if (!audioSource) enabled = false; // audio failed to initialise
if (enabled) onUpdateBegin(false); // create FFT task if (enabled) onUpdateBegin(false); // create FFT task
initDone = true; initDone = true;
@ -869,7 +877,8 @@ class AudioReactive : public Usermod {
* connected() is called every time the WiFi is (re)connected * connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces * Use it to initialize network interfaces
*/ */
void connected() { void connected()
{
if (audioSyncPort > 0 || (audioSyncEnabled & 0x03)) { if (audioSyncPort > 0 || (audioSyncEnabled & 0x03)) {
#ifndef ESP8266 #ifndef ESP8266
udpSyncConnected = fftUdp.beginMulticast(IPAddress(239, 0, 0, 1), audioSyncPort); udpSyncConnected = fftUdp.beginMulticast(IPAddress(239, 0, 0, 1), audioSyncPort);
@ -890,7 +899,10 @@ class AudioReactive : public Usermod {
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here. * Instead, use a timer check as shown here.
*/ */
void loop() { void loop()
{
if (!enabled || strip.isUpdating()) return;
if (!(audioSyncEnabled & 0x02)) { // Only run the sampling code IF we're not in Receive mode if (!(audioSyncEnabled & 0x02)) { // Only run the sampling code IF we're not in Receive mode
if (soundAgc > AGC_NUM_PRESETS) soundAgc = 0; // make sure that AGC preset is valid (to avoid array bounds violation) if (soundAgc > AGC_NUM_PRESETS) soundAgc = 0; // make sure that AGC preset is valid (to avoid array bounds violation)
getSample(); // Sample the microphone getSample(); // Sample the microphone
@ -918,9 +930,6 @@ class AudioReactive : public Usermod {
// update inputLevel Slider based on current AGC gain // update inputLevel Slider based on current AGC gain
if ((soundAgc>0) && agcEffect) { if ((soundAgc>0) && agcEffect) {
static unsigned long last_update_time = 0;
static unsigned long last_kick_time = 0;
static int last_user_inputLevel = 0;
unsigned long now_time = millis(); unsigned long now_time = millis();
// "user kick" feature - if user has moved the slider by at least 32 units, we "kick" AGC gain by 30% (up or down) // "user kick" feature - if user has moved the slider by at least 32 units, we "kick" AGC gain by 30% (up or down)
@ -970,14 +979,16 @@ class AudioReactive : public Usermod {
} }
bool getUMData(um_data_t **data) { bool getUMData(um_data_t **data)
{
if (!data || !enabled) return false; // no pointer provided by caller or not enabled -> exit if (!data || !enabled) return false; // no pointer provided by caller or not enabled -> exit
*data = um_data; *data = um_data;
return true; return true;
} }
void onUpdateBegin(bool init) { void onUpdateBegin(bool init)
{
if (init) vTaskDelete(FFT_Task); // update is about to begin, remove task to prevent crash if (init) vTaskDelete(FFT_Task); // update is about to begin, remove task to prevent crash
else { // update has failed or create task requested else { // update has failed or create task requested
// Define the FFT Task and lock it to core 0 // Define the FFT Task and lock it to core 0
@ -998,19 +1009,30 @@ class AudioReactive : public Usermod {
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor * Below it is shown how this could be used for e.g. a light sensor
*/ */
/*
void addToJsonInfo(JsonObject& root) void addToJsonInfo(JsonObject& root)
{ {
int reading = 20;
//this code adds "u":{"Light":[20," lux"]} to the info object
JsonObject user = root["u"]; JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u"); if (user.isNull()) user = root.createNestedObject("u");
JsonArray lightArr = user.createNestedArray("Light"); //name String uiDomString = F("<button class=\"btn\" onclick=\"requestJson({");
lightArr.add(reading); //value uiDomString += FPSTR(_name);
lightArr.add(" lux"); //unit uiDomString += F(":{");
uiDomString += FPSTR(_enabled);
if (enabled) {
uiDomString += F(":false}});\">");
} else {
uiDomString += F(":true}});\">");
}
uiDomString += F("Audio <i class=\"icons\">&#xe08f;</i>");
uiDomString += F("</button>");
JsonArray infoArr = user.createNestedArray(uiDomString);
if (enabled) {
infoArr.add(FPSTR(_enabled));
} else {
infoArr.add(F("disabled"));
}
} }
*/
/* /*
@ -1029,13 +1051,18 @@ class AudioReactive : public Usermod {
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients * Values in the state object may be modified by connected clients
*/ */
/*
void readFromJsonState(JsonObject& root) void readFromJsonState(JsonObject& root)
{ {
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value if (!initDone) return; // prevent crash on boot applyPreset()
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); bool prevEnabled = enabled;
JsonObject usermod = root[FPSTR(_name)];
if (!usermod.isNull()) {
if (usermod[FPSTR(_enabled)].is<bool>()) {
enabled = usermod[FPSTR(_enabled)].as<bool>();
if (prevEnabled != enabled) onUpdateBegin(!enabled);
}
}
} }
*/
/* /*
@ -1076,7 +1103,7 @@ class AudioReactive : public Usermod {
void addToConfig(JsonObject& root) void addToConfig(JsonObject& root)
{ {
JsonObject top = root.createNestedObject(FPSTR(_name)); JsonObject top = root.createNestedObject(FPSTR(_name));
top[F("enabled")] = enabled; top[FPSTR(_enabled)] = enabled;
JsonObject amic = top.createNestedObject(FPSTR(_analogmic)); JsonObject amic = top.createNestedObject(FPSTR(_analogmic));
amic["pin"] = audioPin; amic["pin"] = audioPin;
@ -1125,7 +1152,7 @@ class AudioReactive : public Usermod {
bool configComplete = !top.isNull(); bool configComplete = !top.isNull();
bool prevEnabled = enabled; bool prevEnabled = enabled;
configComplete &= getJsonValue(top[F("enabled")], enabled); configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
if (initDone && prevEnabled != enabled) { if (initDone && prevEnabled != enabled) {
onUpdateBegin(!enabled); // create or remove FFT task onUpdateBegin(!enabled); // create or remove FFT task
} }
@ -1156,7 +1183,8 @@ class AudioReactive : public Usermod {
} }
void appendConfigData() { void appendConfigData()
{
oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');")); oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');"));
oappend(SET_F("addOption(dd,'Generic Analog',0);")); oappend(SET_F("addOption(dd,'Generic Analog',0);"));
oappend(SET_F("addOption(dd,'Generic I2S',1);")); oappend(SET_F("addOption(dd,'Generic I2S',1);"));
@ -1201,5 +1229,7 @@ class AudioReactive : public Usermod {
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
const char AudioReactive::_name[] PROGMEM = "AudioReactive"; const char AudioReactive::_name[] PROGMEM = "AudioReactive";
const char AudioReactive::_enabled[] PROGMEM = "enabled";
const char AudioReactive::_analogmic[] PROGMEM = "analogmic"; const char AudioReactive::_analogmic[] PROGMEM = "analogmic";
const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic"; const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic";
const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00001";

View File

@ -5872,17 +5872,17 @@ uint16_t WS2812FX::mode_2Dscrollingtext(void) {
const char *text = PSTR("Use segment name"); // fallback if empty segment name const char *text = PSTR("Use segment name"); // fallback if empty segment name
if (SEGMENT.name && strlen(SEGMENT.name)) text = SEGMENT.name; if (SEGMENT.name && strlen(SEGMENT.name)) text = SEGMENT.name;
char lineBuffer[17]; char lineBuffer[17], sec[3];
if (!strstr_P(text, PSTR("#DATETIME"))) { if (strstr_P(text, PSTR("#DATETIME"))) {
byte AmPmHour = hour(localTime); byte AmPmHour = hour(localTime);
boolean isitAM = true; boolean isitAM = true;
if (useAMPM) { if (useAMPM) {
if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; } if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; }
if (AmPmHour == 0) { AmPmHour = 12; } if (AmPmHour == 0) { AmPmHour = 12; }
} }
sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime)); if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
if (useAMPM) sprintf_P(lineBuffer,PSTR("%2d:%02d %s"), AmPmHour, minute(localTime), (isitAM ? "AM" : "PM")); else sprintf_P(sec, PSTR(":%02d"), second(localTime));
else sprintf_P(lineBuffer,PSTR("%2d:%02d:%02d"), AmPmHour, minute(localTime), second(localTime)); sprintf_P(lineBuffer,PSTR("%s %2d %2d:%02d%s"), monthShortStr(month(localTime)), day(localTime), AmPmHour, minute(localTime), sec);
text = lineBuffer; text = lineBuffer;
} }
const int numberOfLetters = strlen(text); const int numberOfLetters = strlen(text);