51
51
#define PLOT_PRINTF (x... )
52
52
#endif
53
53
54
+ #define MAX_PALETTES 3
55
+
54
56
// use audio source class (ESP32 specific)
55
57
#include " audio_source.h"
56
58
constexpr i2s_port_t I2S_PORT = I2S_NUM_0; // I2S port to use (do not change !)
@@ -614,6 +616,8 @@ class AudioReactive : public Usermod {
614
616
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
615
617
bool enabled = false ;
616
618
bool initDone = false ;
619
+ bool addPalettes = false ;
620
+ CRGBPalette16 *palette[MAX_PALETTES];
617
621
618
622
// variables for UDP sound sync
619
623
WiFiUDP fftUdp; // UDP object for sound sync (from WiFi UDP, not Async UDP!)
@@ -652,10 +656,15 @@ class AudioReactive : public Usermod {
652
656
static const char _inputLvl[];
653
657
static const char _analogmic[];
654
658
static const char _digitalmic[];
659
+ static const char _addPalettes[];
655
660
static const char UDP_SYNC_HEADER[];
656
661
static const char UDP_SYNC_HEADER_v1[];
657
662
658
663
// private methods
664
+ void removeAudioPalettes (void );
665
+ void createAudioPalettes (void );
666
+ CRGB getCRGBForBand (int x, int pal);
667
+ void fillAudioPalette (int pal);
659
668
660
669
// //////////////////
661
670
// Debug support //
@@ -1196,6 +1205,7 @@ class AudioReactive : public Usermod {
1196
1205
}
1197
1206
1198
1207
if (enabled) connectUDPSoundSync ();
1208
+ if (enabled && addPalettes) createAudioPalettes ();
1199
1209
initDone = true ;
1200
1210
}
1201
1211
@@ -1358,6 +1368,7 @@ class AudioReactive : public Usermod {
1358
1368
lastTime = millis ();
1359
1369
}
1360
1370
1371
+ for (int i=0 ; i<MAX_PALETTES; i++) fillAudioPalette (i);
1361
1372
}
1362
1373
1363
1374
@@ -1610,6 +1621,11 @@ class AudioReactive : public Usermod {
1610
1621
if (usermod[FPSTR (_enabled)].is <bool >()) {
1611
1622
enabled = usermod[FPSTR (_enabled)].as <bool >();
1612
1623
if (prevEnabled != enabled) onUpdateBegin (!enabled);
1624
+ if (addPalettes) {
1625
+ // add/remove custom/audioreactive palettes
1626
+ if (prevEnabled && !enabled) removeAudioPalettes ();
1627
+ if (!prevEnabled && enabled) createAudioPalettes ();
1628
+ }
1613
1629
}
1614
1630
if (usermod[FPSTR (_inputLvl)].is <int >()) {
1615
1631
inputLevel = min (255 ,max (0 ,usermod[FPSTR (_inputLvl)].as <int >()));
@@ -1657,6 +1673,7 @@ class AudioReactive : public Usermod {
1657
1673
{
1658
1674
JsonObject top = root.createNestedObject (FPSTR (_name));
1659
1675
top[FPSTR (_enabled)] = enabled;
1676
+ top[FPSTR (_addPalettes)] = addPalettes;
1660
1677
1661
1678
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
1662
1679
JsonObject amic = top.createNestedObject (FPSTR (_analogmic));
@@ -1709,8 +1726,11 @@ class AudioReactive : public Usermod {
1709
1726
{
1710
1727
JsonObject top = root[FPSTR (_name)];
1711
1728
bool configComplete = !top.isNull ();
1729
+ bool oldEnabled = enabled;
1730
+ bool oldAddPalettes = addPalettes;
1712
1731
1713
1732
configComplete &= getJsonValue (top[FPSTR (_enabled)], enabled);
1733
+ configComplete &= getJsonValue (top[FPSTR (_addPalettes)], addPalettes);
1714
1734
1715
1735
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
1716
1736
configComplete &= getJsonValue (top[FPSTR (_analogmic)][" pin" ], audioPin);
@@ -1744,6 +1764,11 @@ class AudioReactive : public Usermod {
1744
1764
configComplete &= getJsonValue (top[" sync" ][F (" port" )], audioSyncPort);
1745
1765
configComplete &= getJsonValue (top[" sync" ][F (" mode" )], audioSyncEnabled);
1746
1766
1767
+ if (initDone) {
1768
+ // add/remove custom/audioreactive palettes
1769
+ if ((oldAddPalettes && !addPalettes) || (oldAddPalettes && !enabled)) removeAudioPalettes ();
1770
+ if ((addPalettes && !oldAddPalettes && enabled) || (addPalettes && !oldEnabled && enabled)) createAudioPalettes ();
1771
+ } // else setup() will create palettes
1747
1772
return configComplete;
1748
1773
}
1749
1774
@@ -1819,6 +1844,84 @@ class AudioReactive : public Usermod {
1819
1844
}
1820
1845
};
1821
1846
1847
+ void AudioReactive::removeAudioPalettes (void ) {
1848
+ for (int i=MAX_PALETTES-1 ; i>=0 ; i--) {
1849
+ if (palette[i]) strip.customPalettes .pop_back ();
1850
+ palette[i] = nullptr ;
1851
+ }
1852
+ }
1853
+
1854
+ void AudioReactive::createAudioPalettes (void ) {
1855
+ for (int i=0 ; i<MAX_PALETTES; i++)
1856
+ if (strip.customPalettes .size () < 10 ) {
1857
+ strip.customPalettes .push_back (CRGBPalette16 (CRGB (BLACK)));
1858
+ palette[i] = &strip.customPalettes .back ();
1859
+ } else {
1860
+ palette[i] = nullptr ;
1861
+ }
1862
+ }
1863
+
1864
+ // credit @netmindz ar palette, adapted for usermod @blazoncek
1865
+ CRGB AudioReactive::getCRGBForBand (int x, int pal) {
1866
+ CRGB value;
1867
+ CHSV hsv;
1868
+ int b;
1869
+ switch (pal) {
1870
+ case 2 :
1871
+ b = map (x, 0 , 255 , 0 , NUM_GEQ_CHANNELS/2 ); // convert palette position to lower half of freq band
1872
+ hsv = CHSV (fftResult[b], 255 , x);
1873
+ hsv2rgb_rainbow (hsv, value); // convert to R,G,B
1874
+ break ;
1875
+ case 1 :
1876
+ b = map (x, 1 , 255 , 0 , 10 ); // convert palette position to lower half of freq band
1877
+ hsv = CHSV (fftResult[b], 255 , map (fftResult[b], 0 , 255 , 30 , 255 )); // pick hue
1878
+ hsv2rgb_rainbow (hsv, value); // convert to R,G,B
1879
+ break ;
1880
+ default :
1881
+ if (x == 1 ) {
1882
+ value = CRGB (fftResult[10 ]/2 , fftResult[4 ]/2 , fftResult[0 ]/2 );
1883
+ } else if (x == 255 ) {
1884
+ value = CRGB (fftResult[10 ]/2 , fftResult[0 ]/2 , fftResult[4 ]/2 );
1885
+ } else {
1886
+ value = CRGB (fftResult[0 ]/2 , fftResult[4 ]/2 , fftResult[10 ]/2 );
1887
+ }
1888
+ break ;
1889
+ }
1890
+ return value;
1891
+ }
1892
+
1893
+ void AudioReactive::fillAudioPalette (int pal) {
1894
+ if (pal>=MAX_PALETTES || !palette[pal]) return ; // palette does not exist
1895
+
1896
+ uint8_t tcp[16 ]; // Needs to be 4 times however many colors are being used.
1897
+ // 3 colors = 12, 4 colors = 16, etc.
1898
+
1899
+ tcp[0 ] = 0 ; // anchor of first color - must be zero
1900
+ tcp[1 ] = 0 ;
1901
+ tcp[2 ] = 0 ;
1902
+ tcp[3 ] = 0 ;
1903
+
1904
+ CRGB rgb = getCRGBForBand (1 , pal);
1905
+ tcp[4 ] = 1 ; // anchor of first color
1906
+ tcp[5 ] = rgb.r ;
1907
+ tcp[6 ] = rgb.g ;
1908
+ tcp[7 ] = rgb.b ;
1909
+
1910
+ rgb = getCRGBForBand (128 , pal);
1911
+ tcp[8 ] = 128 ;
1912
+ tcp[9 ] = rgb.r ;
1913
+ tcp[10 ] = rgb.g ;
1914
+ tcp[11 ] = rgb.b ;
1915
+
1916
+ rgb = getCRGBForBand (255 , pal);
1917
+ tcp[12 ] = 255 ; // anchor of last color - must be 255
1918
+ tcp[13 ] = rgb.r ;
1919
+ tcp[14 ] = rgb.g ;
1920
+ tcp[15 ] = rgb.b ;
1921
+
1922
+ palette[pal]->loadDynamicGradientPalette (tcp);
1923
+ }
1924
+
1822
1925
// strings to reduce flash memory usage (used more than twice)
1823
1926
const char AudioReactive::_name[] PROGMEM = " AudioReactive" ;
1824
1927
const char AudioReactive::_enabled[] PROGMEM = " enabled" ;
@@ -1827,5 +1930,6 @@ const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel";
1827
1930
const char AudioReactive::_analogmic[] PROGMEM = " analogmic" ;
1828
1931
#endif
1829
1932
const char AudioReactive::_digitalmic[] PROGMEM = " digitalmic" ;
1933
+ const char AudioReactive::_addPalettes[] PROGMEM = " add-palettes" ;
1830
1934
const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = " 00002" ; // new sync header version, as format no longer compatible with previous structure
1831
1935
const char AudioReactive::UDP_SYNC_HEADER_v1[] PROGMEM = " 00001" ; // old sync header version - need to add backwards-compatibility feature
0 commit comments