Skip to content

Commit 3a8e19d

Browse files
committed
audiosync receive improvements (maintainer edit)
* fixed a few typo's in comments * fixed 8266 specific warning about 'comparison of integer expressions of different signedness' based on recommendations made by @willmmiles: * make sure that audioSyncPacket is the same size (44bytes) on all platforms * use static buffer for receiving (avoids heap fragmentation) * copy receive buffer to local audioSyncPacket struct - avoids alignment problems * esp32 only: to stay in sync with UDP, Udp.flush() is needed when Udp.parsePacket() is _not_ followed by Udp.read()
1 parent cc9db02 commit 3a8e19d

File tree

1 file changed

+36
-28
lines changed

1 file changed

+36
-28
lines changed

usermods/audioreactive/audio_reactive.h

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ static uint8_t soundAgc = 0; // Automagic gain control: 0 - n
7676
static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency
7777
static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency
7878
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
79-
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
79+
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
8080
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
8181
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
8282

@@ -94,7 +94,7 @@ static uint16_t decayTime = 1400; // int: decay time in milliseconds
9494

9595
// peak detection
9696
#ifdef ARDUINO_ARCH_ESP32
97-
static void detectSamplePeak(void); // peak detection function (needs scaled FFT reasults in vReal[]) - no used for 8266 receive-only mode
97+
static void detectSamplePeak(void); // peak detection function (needs scaled FFT results in vReal[]) - no used for 8266 receive-only mode
9898
#endif
9999
static void autoResetPeak(void); // peak auto-reset function
100100
static uint8_t maxVol = 31; // (was 10) Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
@@ -587,19 +587,21 @@ class AudioReactive : public Usermod {
587587
#endif
588588
#endif
589589

590-
// new "V2" audiosync struct - 40 Bytes
591-
struct audioSyncPacket {
592-
char header[6]; // 06 Bytes
593-
float sampleRaw; // 04 Bytes - either "sampleRaw" or "rawSampleAgc" depending on soundAgc setting
594-
float sampleSmth; // 04 Bytes - either "sampleAvg" or "sampleAgc" depending on soundAgc setting
595-
uint8_t samplePeak; // 01 Bytes - 0 no peak; >=1 peak detected. In future, this will also provide peak Magnitude
596-
uint8_t reserved1; // 01 Bytes - for future extensions - not used yet
597-
uint8_t fftResult[16]; // 16 Bytes
598-
float FFT_Magnitude; // 04 Bytes
599-
float FFT_MajorPeak; // 04 Bytes
590+
// new "V2" audiosync struct - 44 Bytes
591+
struct __attribute__ ((packed)) audioSyncPacket { // "packed" ensures that there are no additional gaps
592+
char header[6]; // 06 Bytes offset 0
593+
uint8_t reserved1[2]; // 02 Bytes, offset 6 - gap required by the compiler - not used yet
594+
float sampleRaw; // 04 Bytes offset 8 - either "sampleRaw" or "rawSampleAgc" depending on soundAgc setting
595+
float sampleSmth; // 04 Bytes offset 12 - either "sampleAvg" or "sampleAgc" depending on soundAgc setting
596+
uint8_t samplePeak; // 01 Bytes offset 16 - 0 no peak; >=1 peak detected. In future, this will also provide peak Magnitude
597+
uint8_t reserved2; // 01 Bytes offset 17 - for future extensions - not used yet
598+
uint8_t fftResult[16]; // 16 Bytes offset 18
599+
uint16_t reserved3; // 02 Bytes, offset 34 - gap required by the compiler - not used yet
600+
float FFT_Magnitude; // 04 Bytes offset 36
601+
float FFT_MajorPeak; // 04 Bytes offset 40
600602
};
601603

602-
// old "V1" audiosync struct - 83 Bytes - for backwards compatibility
604+
// old "V1" audiosync struct - 83 Bytes payload, 88 bytes total (with padding added by compiler) - for backwards compatibility
603605
struct audioSyncPacket_v1 {
604606
char header[6]; // 06 Bytes
605607
uint8_t myVals[32]; // 32 Bytes
@@ -612,6 +614,8 @@ class AudioReactive : public Usermod {
612614
double FFT_MajorPeak; // 08 Bytes
613615
};
614616

617+
#define UDPSOUND_MAX_PACKET 88 // max packet size for audiosync
618+
615619
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
616620
#ifdef UM_AUDIOREACTIVE_ENABLE
617621
bool enabled = true;
@@ -997,7 +1001,6 @@ class AudioReactive : public Usermod {
9971001
transmitData.sampleSmth = (soundAgc) ? sampleAgc : sampleAvg;
9981002
transmitData.samplePeak = udpSamplePeak ? 1:0;
9991003
udpSamplePeak = false; // Reset udpSamplePeak after we've transmitted it
1000-
transmitData.reserved1 = 0;
10011004

10021005
for (int i = 0; i < NUM_GEQ_CHANNELS; i++) {
10031006
transmitData.fftResult[i] = (uint8_t)constrain(fftResult[i], 0, 254);
@@ -1023,10 +1026,13 @@ class AudioReactive : public Usermod {
10231026
}
10241027

10251028
void decodeAudioData(int packetSize, uint8_t *fftBuff) {
1026-
audioSyncPacket *receivedPacket = reinterpret_cast<audioSyncPacket*>(fftBuff);
1029+
audioSyncPacket receivedPacket;
1030+
memset(&receivedPacket, 0, sizeof(receivedPacket)); // start clean
1031+
memcpy(&receivedPacket, fftBuff, min((unsigned)packetSize, (unsigned)sizeof(receivedPacket))); // don't violate alignment - thanks @willmmiles#
1032+
10271033
// update samples for effects
1028-
volumeSmth = fmaxf(receivedPacket->sampleSmth, 0.0f);
1029-
volumeRaw = fmaxf(receivedPacket->sampleRaw, 0.0f);
1034+
volumeSmth = fmaxf(receivedPacket.sampleSmth, 0.0f);
1035+
volumeRaw = fmaxf(receivedPacket.sampleRaw, 0.0f);
10301036
#ifdef ARDUINO_ARCH_ESP32
10311037
// update internal samples
10321038
sampleRaw = volumeRaw;
@@ -1039,15 +1045,15 @@ class AudioReactive : public Usermod {
10391045
// If it's true already, then the animation still needs to respond.
10401046
autoResetPeak();
10411047
if (!samplePeak) {
1042-
samplePeak = receivedPacket->samplePeak >0 ? true:false;
1048+
samplePeak = receivedPacket.samplePeak >0 ? true:false;
10431049
if (samplePeak) timeOfPeak = millis();
10441050
//userVar1 = samplePeak;
10451051
}
10461052
//These values are only computed by ESP32
1047-
for (int i = 0; i < NUM_GEQ_CHANNELS; i++) fftResult[i] = receivedPacket->fftResult[i];
1048-
my_magnitude = fmaxf(receivedPacket->FFT_Magnitude, 0.0f);
1053+
for (int i = 0; i < NUM_GEQ_CHANNELS; i++) fftResult[i] = receivedPacket.fftResult[i];
1054+
my_magnitude = fmaxf(receivedPacket.FFT_Magnitude, 0.0f);
10491055
FFT_Magnitude = my_magnitude;
1050-
FFT_MajorPeak = constrain(receivedPacket->FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects
1056+
FFT_MajorPeak = constrain(receivedPacket.FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects
10511057
}
10521058

10531059
void decodeAudioData_v1(int packetSize, uint8_t *fftBuff) {
@@ -1084,9 +1090,12 @@ class AudioReactive : public Usermod {
10841090
bool haveFreshData = false;
10851091

10861092
size_t packetSize = fftUdp.parsePacket();
1087-
if (packetSize > 5) {
1093+
#ifdef ARDUINO_ARCH_ESP32
1094+
if ((packetSize > 0) && ((packetSize < 5) || (packetSize > UDPSOUND_MAX_PACKET))) fftUdp.flush(); // discard invalid packets (too small or too big) - only works on esp32
1095+
#endif
1096+
if ((packetSize > 5) && (packetSize <= UDPSOUND_MAX_PACKET)) {
10881097
//DEBUGSR_PRINTLN("Received UDP Sync Packet");
1089-
uint8_t fftBuff[packetSize];
1098+
static uint8_t fftBuff[UDPSOUND_MAX_PACKET+1] = { 0 }; // static buffer for receiving, to reuse the same memory and avoid heap fragmentation
10901099
fftUdp.read(fftBuff, packetSize);
10911100

10921101
// VERIFY THAT THIS IS A COMPATIBLE PACKET
@@ -1229,7 +1238,7 @@ class AudioReactive : public Usermod {
12291238

12301239
if (!audioSource) enabled = false; // audio failed to initialise
12311240
#endif
1232-
if (enabled) onUpdateBegin(false); // create FFT task, and initailize network
1241+
if (enabled) onUpdateBegin(false); // create FFT task, and initialize network
12331242

12341243

12351244
#ifdef ARDUINO_ARCH_ESP32
@@ -1243,7 +1252,7 @@ class AudioReactive : public Usermod {
12431252
disableSoundProcessing = true;
12441253
}
12451254
#endif
1246-
if (enabled) disableSoundProcessing = false; // all good - enable audio processing
1255+
if (enabled) disableSoundProcessing = false; // all good - enable audio processing
12471256
if (enabled) connectUDPSoundSync();
12481257
if (enabled && addPalettes) createAudioPalettes();
12491258
initDone = true;
@@ -1803,7 +1812,6 @@ class AudioReactive : public Usermod {
18031812
dynLim[F("rise")] = attackTime;
18041813
dynLim[F("fall")] = decayTime;
18051814

1806-
18071815
JsonObject sync = top.createNestedObject("sync");
18081816
sync["port"] = audioSyncPort;
18091817
sync["mode"] = audioSyncEnabled;
@@ -2008,8 +2016,8 @@ CRGB AudioReactive::getCRGBForBand(int x, int pal) {
20082016
void AudioReactive::fillAudioPalettes() {
20092017
if (!palettes) return;
20102018
size_t lastCustPalette = strip.customPalettes.size();
2011-
if (lastCustPalette >= palettes) lastCustPalette -= palettes;
2012-
for (size_t pal=0; pal<palettes; pal++) {
2019+
if (int(lastCustPalette) >= palettes) lastCustPalette -= palettes;
2020+
for (int pal=0; pal<palettes; pal++) {
20132021
uint8_t tcp[16]; // Needs to be 4 times however many colors are being used.
20142022
// 3 colors = 12, 4 colors = 16, etc.
20152023

0 commit comments

Comments
 (0)