diff --git a/README.md b/README.md index 8eeb314..a9c5686 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,16 @@ Work is in progress... --- ## Version history +#### v0.6.494 +- adding VU meter for displays ST7735 160x128, ST7735 128x128, ILI9341 320x240, ST7789 320x240 \ + option ENABLE_VU_METER (see [myoptions.h](exsamples/myoptions.h#L113) for exsample) \ + **!!! Important !!!** \ + if you enable this feathure on the esp32 wroom, due to lack of memory, you must modify the file Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp \ + replace the line 221 \ + xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); \ + with \ + xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 / 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); + #### v0.6.450 **!!! a [full update](#update-over-web-interface) with Sketch data upload is required. After updating please press CTRL+F5 in browser !!!** - adding an IR remote control has been moved to the web-interface (more info in [Controls.md](Controls.md#ir-receiver)) diff --git a/exsamples/myoptions.h b/exsamples/myoptions.h index 7a21f83..beeddd5 100644 --- a/exsamples/myoptions.h +++ b/exsamples/myoptions.h @@ -110,7 +110,20 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti //#define SNTP_SERVER "pool.ntp.org", "0.ru.pool.ntp.org" /* custom ntp servers min 1 max 3 comma separated values */ //#define I2S_INTERNAL false /* If true - use esp32 internal DAC */ //#define SOFT_AP_REBOOT_DELAY 0 /* Delay in milliseconds after which ESP is rebooting if it is in softAP mode (0 - disabled) */ - +//#define ENABLE_VU_METER false /* enable? vu meter for some displays */ +/* + * !!! Important !!! + * if you enable this feathure on the esp32 wroom, due to lack of memory, you must modify the file Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp + * replace the line 221 + * xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); + * with + * xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 / 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); +*/ +/* VU settings. See the default settings for your display in file yoRadio/display_vu.h */ +/*****************************************************************************************************************************************************************************/ +/* vu left | vu top | band width | band height | band space | num of bands | max samples | horisontal | Max Bands Color | Min Bands Color */ +/*****************************************************************************************************************************************************************************/ +//#define VU_PARAMS { VU_X = 4, VU_Y = 60, VU_BW = 10, VU_BH = 34, VU_BS = 2, VU_NB = 8, VU_BMS = 2, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = SILVER } /******************************************/ /* IR control */ diff --git a/yoRadio/display.cpp b/yoRadio/display.cpp index 380c1db..affa523 100644 --- a/yoRadio/display.cpp +++ b/yoRadio/display.cpp @@ -3,7 +3,9 @@ #include "WiFi.h" #include "time.h" #include "display.h" - +#if ENABLE_VU_METER +#include "display_vu.h" +#endif #include "player.h" #include "netserver.h" #include "network.h" @@ -453,6 +455,9 @@ void Display::loop() { } dsp.loop(); if (dsp_on_loop) dsp_on_loop(&dsp); +#if ENABLE_VU_METER + drawVU(&dsp); +#endif } void Display::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) { diff --git a/yoRadio/display_vu.h b/yoRadio/display_vu.h new file mode 100644 index 0000000..ece50f6 --- /dev/null +++ b/yoRadio/display_vu.h @@ -0,0 +1,80 @@ +#if ENABLE_VU_METER +#ifndef display_vu_h +#define display_vu_h +#include "player.h" + +#ifdef VU_PARAMS +enum : uint16_t VU_PARAMS; +#else +/*****************************************************************************************************************************************************************************/ +/* vu left | vu top | band width | band height | band space |num of bands |max samples | horisontal | Max Bands Color | Min Bands Color */ +/*****************************************************************************************************************************************************************************/ +#if DSP_MODEL==DSP_ST7735 && DTYPE==INITR_BLACKTAB /* ST7735 160x128 */ +enum : uint16_t { VU_X = 4, VU_Y = 50, VU_BW = 10, VU_BH = 44, VU_BS = 2, VU_NB = 8, VU_BMS = 2, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = SILVER }; +#elif DSP_MODEL==DSP_ST7735 && DTYPE==INITR_144GREENTAB /* ST7735 128x128 */ +enum : uint16_t { VU_X = 4, VU_Y = 45, VU_BW = 60, VU_BH = 8, VU_BS = 0, VU_NB = 10, VU_BMS = 3, VU_HOR = 1, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY }; +#elif DSP_MODEL==DSP_ILI9341 /* ILI9341 320x240 */ +enum : uint16_t { VU_X = 4, VU_Y = 100, VU_BW = 20, VU_BH = 86, VU_BS = 4, VU_NB = 10, VU_BMS = 2, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY }; +#elif DSP_MODEL==DSP_ST7789 /* ST7789 320x240 */ +enum : uint16_t { VU_X = 4, VU_Y = 100, VU_BW = 20, VU_BH = 86, VU_BS = 4, VU_NB = 10, VU_BMS = 3, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY }; +#else +#error YOUR DISPLAY DOES NOT SUPPORT ENABLE_VU_METER FEATURE YET +#endif +#endif //VU_PARAMS + +/*****************************************************************************************************************************************************************************/ + +void drawVU(DspCore *dsp); + +GFXcanvas16 gfxc(VU_BW*2+VU_BS,VU_BH); + +void drawVU(DspCore *dsp){ + if((display.mode!=PLAYER && display.mode!=VOL)) return; + player.getVUlevel(); + static uint16_t samples_cnt, measL, measR; + samples_cnt++; + uint16_t dimension = VU_HOR?VU_BW:VU_BH; + uint8_t L = map((VS1053_CS!=255)?player.vuLeft:log(player.vuLeft)*38+45, 255, 0, 0, dimension); + uint8_t R = map((VS1053_CS!=255)?player.vuRight:log(player.vuRight)*38+45, 255, 0, 0, dimension); + if(player.isRunning()){ + if(L>measL) measL=L; + if(R>measR) measR=R; + }else{ + if(measL<255) measL+=2; + if(measR<255) measR+=2; + } +#if VS1053_CS==255 + if(samples_cntVU_BW-(VU_BW/VU_NB)*4)?VU_COLOR_MAX:VU_COLOR_MIN; + gfxc.fillRect(i, 0, h, VU_BH, bandColor); + gfxc.fillRect(i+VU_BW+VU_BS, 0, h, VU_BH, bandColor); + }else{ + uint16_t bandColor = (i<(VU_BH/VU_NB)*3)?VU_COLOR_MAX:VU_COLOR_MIN; + gfxc.fillRect(0, i, VU_BW, h, bandColor); + gfxc.fillRect(VU_BW+VU_BS, i, VU_BW, h, bandColor); + } + } + } + if(VU_HOR){ + gfxc.fillRect(VU_BW-measL, 0, measL, VU_BW, TFT_BG); + gfxc.fillRect(VU_BW*2+VU_BS-measR, 0, measR, VU_BW, TFT_BG); + dsp->drawRGBBitmap (VU_X, VU_Y, gfxc.getBuffer(), 120, VU_BH); + }else{ + gfxc.fillRect(0, 0, VU_BW, measL, TFT_BG); + gfxc.fillRect(VU_BW+VU_BS, 0, VU_BW, measR, TFT_BG); + dsp->drawRGBBitmap (VU_X, VU_Y, gfxc.getBuffer(), VU_BW*2+VU_BS, VU_BH); + } + if(player.isRunning()){ + measL=0; + measR=0; + } +} + +#endif +#endif diff --git a/yoRadio/options.h b/yoRadio/options.h index 351a421..8cafd9b 100644 --- a/yoRadio/options.h +++ b/yoRadio/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define VERSION "0.6.450" +#define VERSION "0.6.494" /******************************************************* DO NOT EDIT THIS FILE. @@ -225,6 +225,17 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti #ifndef SOFT_AP_REBOOT_DELAY #define SOFT_AP_REBOOT_DELAY 0 // Delay in ms after which ESP is rebooting if it is in softAP mode (0 - disabled) #endif +#ifndef ENABLE_VU_METER + #define ENABLE_VU_METER false // enable? vu meter for some displays +/* + * !!! Important !!! + * if you enable this feathure on the esp32 wroom, due to lack of memory, you must modify the file Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp + * replace the line 221 + * xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); + * with + * xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 / 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); +*/ +#endif /* *** ST7735 display submodel *** INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html diff --git a/yoRadio/src/audioI2S/Audio.cpp b/yoRadio/src/audioI2S/Audio.cpp index 4f36a69..54c31f5 100644 --- a/yoRadio/src/audioI2S/Audio.cpp +++ b/yoRadio/src/audioI2S/Audio.cpp @@ -4269,7 +4269,8 @@ int32_t Audio::Gain(int16_t s[2]) { step = step * m_balance * 16; r = (uint8_t)(step); } - + vuLeft = s[LEFTCHANNEL] >> 7; + vuRight = s[RIGHTCHANNEL] >> 7; v[LEFTCHANNEL] = (s[LEFTCHANNEL] * (m_vol - l)) >> 8; v[RIGHTCHANNEL]= (s[RIGHTCHANNEL] * (m_vol - r)) >> 8; diff --git a/yoRadio/src/audioI2S/AudioEx.h b/yoRadio/src/audioI2S/AudioEx.h index d45de61..c853225 100644 --- a/yoRadio/src/audioI2S/AudioEx.h +++ b/yoRadio/src/audioI2S/AudioEx.h @@ -186,7 +186,10 @@ public: uint32_t getAudioCurrentTime(); uint32_t getTotalPlayingTime(); void setDefaults(); - + /* VU METER */ + void setVUmeter() {}; + void getVUlevel() {}; + uint8_t vuLeft, vuRight; SemaphoreHandle_t mutex_pl=NULL; esp_err_t i2s_mclk_pin_select(const uint8_t pin); diff --git a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp index ea23873..6c5725e 100644 --- a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp +++ b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp @@ -331,6 +331,8 @@ void Audio::begin(){ write_register(SCI_AUDATA, 44100 + 1); // 44.1kHz + stereo // The next clocksetting allows SPI clocking at 5 MHz, 4 MHz is safe then. write_register(SCI_CLOCKF, 6 << 12); // Normal clock settings multiplyer 3.0=12.2 MHz + //set vu meter + setVUmeter(); //SPI Clock to 4 MHz. Now you can set high speed SPI clock. VS1053_SPI=SPISettings(6700000, MSBFIRST, SPI_MODE0); // SPIDIV 12 -> 80/12=6.66 MHz write_register(SCI_MODE, _BV (SM_SDINEW) | _BV(SM_LINE1)); @@ -353,6 +355,16 @@ size_t Audio::bufferFree(){ return InBuff.freeSpace(); } //--------------------------------------------------------------------------------------------------------------------- +uint32_t Audio::inBufferFilled() { + // current audio input buffer fillsize in bytes + return InBuff.bufferFilled(); +} +//--------------------------------------------------------------------------------------------------------------------- +uint32_t Audio::inBufferFree() { + // current audio input buffer free space in bytes + return InBuff.freeSpace(); +} +//--------------------------------------------------------------------------------------------------------------------- void Audio::setVolume(uint8_t vol){ // Set volume. Both left and right. @@ -1542,6 +1554,45 @@ void Audio::setDefaults(){ m_f_tts = false; // text to speech m_f_localfile = false; } +//------------------------------------------------------------------------------ +/** + * \brief enable VSdsp VU Meter + * + * \param[in] enable when set will enable the VU meter + * + * Writes the SS_VU_ENABLE bit of the SCI_STATUS register to enable VU meter on + * board to the VSdsp. + * + * See data patches data sheet VU meter for details. + * \warning This feature is only available with patches that support VU meter. + * \n The VU meter takes about 0.2MHz of processing power with 48 kHz samplerate. + */ +void Audio::setVUmeter() { + if(!ENABLE_VU_METER) return; + uint16_t MP3Status = read_register(SCI_STATUS); + write_register(SCI_STATUS, MP3Status | _BV(9)); +} + +//------------------------------------------------------------------------------ +/** + * \brief get current measured VU Meter + * + * Returns the calculated peak sample values from both channels in 3 dB + * increaments through. Where the high byte represent the left channel, + * and the low bytes the right channel. + * + * Values from 0 to 31 are valid for both channels. + * + * \warning This feature is only available with patches that support VU meter. + */ +void Audio::getVUlevel() { + if(!ENABLE_VU_METER) return; + int16_t reg = read_register(SCI_AICTRL3); + uint8_t rl = map((uint8_t)reg, 81, 92, 0, 255); + uint8_t rr = map((uint8_t)(reg >> 8), 81, 92, 0, 255); + if(rl>30 || !isRunning()) vuLeft = rl; + if(rr>30 || !isRunning()) vuRight = rr; +} //--------------------------------------------------------------------------------------------------------------------- bool Audio::connecttohost(String host){ return connecttohost(host.c_str()); diff --git a/yoRadio/src/audioVS1053/audioVS1053Ex.h b/yoRadio/src/audioVS1053/audioVS1053Ex.h index 17dfaa9..c518944 100644 --- a/yoRadio/src/audioVS1053/audioVS1053Ex.h +++ b/yoRadio/src/audioVS1053/audioVS1053Ex.h @@ -241,7 +241,6 @@ protected: void loadUserCode(); - public: // Constructor. Only sets pin values. Doesn't touch the chip. Be sure to call begin()! Audio ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t spi = VSPI, uint8_t mosi = 23, uint8_t miso = 19, uint8_t sclk = 18); @@ -269,11 +268,17 @@ public: SemaphoreHandle_t mutex_pl=NULL; size_t bufferFilled(); size_t bufferFree(); + uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer + uint32_t inBufferFree(); // returns the number of free bytes in the inputbuffer bool isRunning() {/*Serial.printf("m_f_running=%d\n", m_f_running); */return m_f_running;} void setBalance(int8_t bal = 0); void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass); void setDefaults(); void forceMono(bool m) {} // TODO + /* VU METER */ + void setVUmeter(); + void getVUlevel(); + uint8_t vuLeft, vuRight; // implement several function with respect to the index of string bool startsWith (const char* base, const char* str) { return (strstr(base, str) - base) == 0;} bool endsWith (const char* base, const char* str) { diff --git a/yoRadio/src/displays/displayILI9225.cpp b/yoRadio/src/displays/displayILI9225.cpp index c72fe73..967bf46 100644 --- a/yoRadio/src/displays/displayILI9225.cpp +++ b/yoRadio/src/displays/displayILI9225.cpp @@ -284,7 +284,6 @@ void DspCore::displayHeapForDebug() { fillRect(TFT_FRAMEWDT, vTop, swidth - TFT_FRAMEWDT / 2, 7, TFT_BG); sprintf(buf, "%d / %d", ESP.getFreeHeap(), ESP.getMaxAllocHeap()); print(buf); -#if VS1053_CS==255 // audio buffer; fillRect(0, sheight - 2, swidth, 2, TFT_BG); int astored = player.inBufferFilled(); @@ -292,7 +291,6 @@ void DspCore::displayHeapForDebug() { int aprcnt = 100 * astored / (astored + afree); byte sbw = map(aprcnt, 0, 100 , 0, swidth); fillRect(0, sheight - 2, sbw, 2, SILVER); -#endif } void DspCore::printClock(const char* timestr) { diff --git a/yoRadio/src/displays/displayILI9341.cpp b/yoRadio/src/displays/displayILI9341.cpp index 018e856..ecba117 100644 --- a/yoRadio/src/displays/displayILI9341.cpp +++ b/yoRadio/src/displays/displayILI9341.cpp @@ -121,6 +121,7 @@ void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) { setTextSize(1); screenwidth = width(); screenheight = height(); + Serial.printf("ILI9341 %dx%d\n", screenwidth, screenheight); swidth = screenwidth; sheight = screenheight; } @@ -208,7 +209,6 @@ void DspCore::displayHeapForDebug() { print(ESP.getFreeHeap()); print(" / "); print(ESP.getMaxAllocHeap()); -#if VS1053_CS==255 // audio buffer; fillRect(0, sheight - 2, swidth, 2, TFT_BG); int astored = player.inBufferFilled(); @@ -216,7 +216,6 @@ void DspCore::displayHeapForDebug() { int aprcnt = 100 * astored / (astored + afree); byte sbw = map(aprcnt, 0, 100 , 0, swidth); fillRect(0, sheight - 2, sbw, 2, SILVER); -#endif } void DspCore::printClock(const char* timestr) { diff --git a/yoRadio/src/displays/displaySSD1327.cpp b/yoRadio/src/displays/displaySSD1327.cpp index 0509b22..0f8e99e 100644 --- a/yoRadio/src/displays/displaySSD1327.cpp +++ b/yoRadio/src/displays/displaySSD1327.cpp @@ -220,7 +220,6 @@ void DspCore::displayHeapForDebug() { print(ESP.getFreeHeap()); print(" / "); print(ESP.getMaxAllocHeap()); -#if VS1053_CS==255 // audio buffer; fillRect(0, sheight - 2, swidth, 2, TFT_BG); int astored = player.inBufferFilled(); @@ -228,7 +227,6 @@ void DspCore::displayHeapForDebug() { int aprcnt = 100 * astored / (astored + afree); byte sbw = map(aprcnt, 0, 100 , 0, swidth); fillRect(0, sheight - 2, sbw, 2, DARK_GRAY); -#endif } void DspCore::setClockBounds(){ diff --git a/yoRadio/src/displays/displayST7735.cpp b/yoRadio/src/displays/displayST7735.cpp index 62c0198..8beea04 100644 --- a/yoRadio/src/displays/displayST7735.cpp +++ b/yoRadio/src/displays/displayST7735.cpp @@ -16,6 +16,12 @@ #define DEF_SPI_FREQ 40000000UL /* set it to 0 for system default */ #endif +#if ENABLE_VU_METER && DTYPE==INITR_BLACKTAB +#define CLOCK_DELTA 12 +#else +#define CLOCK_DELTA 0 +#endif + #define TAKE_MUTEX() if(player.mutex_pl) xSemaphoreTake(player.mutex_pl, portMAX_DELAY) #define GIVE_MUTEX() if(player.mutex_pl) xSemaphoreGive(player.mutex_pl) @@ -220,7 +226,6 @@ void DspCore::displayHeapForDebug() { print(ESP.getFreeHeap()); print(" / "); print(ESP.getMaxAllocHeap()); -#if VS1053_CS==255 // audio buffer; fillRect(0, sheight - 2, swidth, 2, TFT_BG); int astored = player.inBufferFilled(); @@ -229,7 +234,6 @@ void DspCore::displayHeapForDebug() { byte sbw = map(aprcnt, 0, 100 , 0, swidth); fillRect(0, sheight - 2, sbw, 2, SILVER); #endif -#endif } void DspCore::setClockBounds(){ @@ -263,10 +267,10 @@ void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){ setFont(&DS_DIGI28pt7b); if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){ getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot); - setCursor((swidth - wot) / 2 - 4, clockY+28+6); + setCursor((swidth - wot) / 2 - 4 + CLOCK_DELTA, clockY+28+6); setTextColor(TFT_BG); print(oldTimeBuf); - dot = (swidth - wot) / 2 - 4; + dot = (swidth - wot) / 2 - 4 + CLOCK_DELTA; /* dots */ strlcpy(tmpBuf, oldTimeBuf, 3); getTextBounds(tmpBuf, 0, 0, &x, &y, &ncwidth, &ncheight); @@ -279,8 +283,8 @@ void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){ setTextSize(1); getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight); setTextColor(TFT_LOGO); - setCursor((swidth - ncwidth) / 2 - 4, clockY+28+6); - dot = (swidth - ncwidth) / 2 - 4; + setCursor((swidth - ncwidth) / 2 - 4 + CLOCK_DELTA, clockY+28+6); + dot = (swidth - ncwidth) / 2 - 4 + CLOCK_DELTA; setTextSize(1); print(timeBuf); /* dots */ diff --git a/yoRadio/src/displays/displayST7789.cpp b/yoRadio/src/displays/displayST7789.cpp index 46891bd..c5cc37e 100644 --- a/yoRadio/src/displays/displayST7789.cpp +++ b/yoRadio/src/displays/displayST7789.cpp @@ -216,7 +216,6 @@ void DspCore::displayHeapForDebug() { print(ESP.getFreeHeap()); print(" / "); print(ESP.getMaxAllocHeap()); -#if VS1053_CS==255 // audio buffer; fillRect(0, sheight - 2, swidth, 2, TFT_BG); int astored = player.inBufferFilled(); @@ -224,7 +223,6 @@ void DspCore::displayHeapForDebug() { int aprcnt = 100 * astored / (astored + afree); byte sbw = map(aprcnt, 0, 100 , 0, swidth); fillRect(0, sheight - 2, sbw, 2, SILVER); -#endif yield(); }