diff --git a/README.md b/README.md index bc2a991..11f6cf9 100644 --- a/README.md +++ b/README.md @@ -234,11 +234,15 @@ Work is in progress... --- ## Version history +### v0.9.390 +- updated the VU meter algorithms - shamelessly borrowed from @schreibfaul1, ([thanks a lot!](https://github.com/schreibfaul1/ESP32-audioI2S/blob/1296374fc513a6d6bfaa3b1ca08f6ba938b18d99/src/Audio.cpp#L5030)) +- fixed the magic error "HSPI" redefined. + ### v0.9.380 - fixed compilation error for ESP32 cores >= 3.1.0 - fixed freezing error with incorrectly configured RTC module - [www|uart|telnet] new command `mode` - change SD/WEB mode. (0 - WEB, 1 - SD, 2 - Toggle) - example: http:///?mode=2 + example: http://\/?mode=2 #### v0.9.375 - fixed the issue with saving settings for TIMEZONE. diff --git a/yoRadio/src/audioI2S/Audio.cpp b/yoRadio/src/audioI2S/Audio.cpp index 7fb0d72..42dbebd 100644 --- a/yoRadio/src/audioI2S/Audio.cpp +++ b/yoRadio/src/audioI2S/Audio.cpp @@ -2335,11 +2335,6 @@ bool Audio::pauseResume() { bool Audio::playChunk() { // If we've got data, try and pump it out.. int16_t sample[2]; - /* VU Meter ************************************************************************************************************/ - /* По мотивам https://github.com/schreibfaul1/ESP32-audioI2S/pull/170/commits/6cce84217e5bc8f2f8925936affc84576932a29b */ - uint8_t maxl = 0, maxr = 0; - uint8_t minl = 0xFF, minr = 0xFF; - /************************************************************************************************************ VU Meter */ if(getBitsPerSample() == 8) { if(getChannels() == 1) { while(m_validSamples) { @@ -2347,19 +2342,11 @@ bool Audio::playChunk() { uint8_t y = (m_outBuff[m_curSample] & 0xFF00) >> 8; sample[LEFTCHANNEL] = x; sample[RIGHTCHANNEL] = x; - if(sample[LEFTCHANNEL] > maxl ) maxl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] > maxr ) maxr = sample[RIGHTCHANNEL]; - if(sample[LEFTCHANNEL] < minl ) minl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] < minr ) minr = sample[RIGHTCHANNEL]; while(1) { if(playSample(sample)) break; } // Can't send? sample[LEFTCHANNEL] = y; sample[RIGHTCHANNEL] = y; - if(sample[LEFTCHANNEL] > maxl ) maxl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] > maxr ) maxr = sample[RIGHTCHANNEL]; - if(sample[LEFTCHANNEL] < minl ) minl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] < minr ) minr = sample[RIGHTCHANNEL]; while(1) { if(playSample(sample)) break; } // Can't send? @@ -2380,10 +2367,6 @@ bool Audio::playChunk() { sample[LEFTCHANNEL] = xy; sample[RIGHTCHANNEL] = xy; } - if(sample[LEFTCHANNEL] > maxl ) maxl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] > maxr ) maxr = sample[RIGHTCHANNEL]; - if(sample[LEFTCHANNEL] < minl ) minl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] < minr ) minr = sample[RIGHTCHANNEL]; while(1) { if(playSample(sample)) break; } // Can't send? @@ -2391,8 +2374,6 @@ bool Audio::playChunk() { m_curSample++; } } - vuLeft = maxl - minl; - vuRight = maxr - minr; m_curSample = 0; return true; } @@ -2401,10 +2382,6 @@ bool Audio::playChunk() { while(m_validSamples) { sample[LEFTCHANNEL] = m_outBuff[m_curSample]; sample[RIGHTCHANNEL] = m_outBuff[m_curSample]; - if(sample[LEFTCHANNEL] > maxl ) maxl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] > maxr ) maxr = sample[RIGHTCHANNEL]; - if(sample[LEFTCHANNEL] < minl ) minl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] < minr ) minr = sample[RIGHTCHANNEL]; if(!playSample(sample)) { log_e("can't send"); return false; @@ -2425,17 +2402,11 @@ bool Audio::playChunk() { sample[LEFTCHANNEL] = xy; sample[RIGHTCHANNEL] = xy; } - if(sample[LEFTCHANNEL] > maxl ) maxl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] > maxr ) maxr = sample[RIGHTCHANNEL]; - if(sample[LEFTCHANNEL] < minl ) minl = sample[LEFTCHANNEL]; - if(sample[RIGHTCHANNEL] < minr ) minr = sample[RIGHTCHANNEL]; playSample(sample); m_validSamples--; m_curSample++; } } - vuLeft = maxl - minl; - vuRight = maxr - minr; m_curSample = 0; return true; } @@ -2444,10 +2415,86 @@ bool Audio::playChunk() { stopSong(); return false; } + +/* + * Shamelessly borrowed from @schreibfaul1 https://github.com/schreibfaul1/ESP32-audioI2S/blob/1296374fc513a6d6bfaa3b1ca08f6ba938b18d99/src/Audio.cpp#L5030 + */ +void Audio::_computeVUlevel(int16_t sample[2]) { + if(!config.store.vumeter) return; + static uint8_t sampleArray[2][4][8] = {0}; + static uint8_t cnt0 = 0, cnt1 = 0, cnt2 = 0, cnt3 = 0, cnt4 = 0; + static bool f_vu = false; + + auto avg = [&](uint8_t* sampArr) { // lambda, inner function, compute the average of 8 samples + uint16_t av = 0; + for(int i = 0; i < 8; i++) { av += sampArr[i]; } + return av >> 3; + }; + + auto largest = [&](uint8_t* sampArr) { // lambda, inner function, compute the largest of 8 samples + uint16_t maxValue = 0; + for(int i = 0; i < 8; i++) { + if(maxValue < sampArr[i]) maxValue = sampArr[i]; + } + return maxValue; + }; + + if(cnt0 == 64) { + cnt0 = 0; + cnt1++; + } + if(cnt1 == 8) { + cnt1 = 0; + cnt2++; + } + if(cnt2 == 8) { + cnt2 = 0; + cnt3++; + } + if(cnt3 == 8) { + cnt3 = 0; + cnt4++; + f_vu = true; + } + if(cnt4 == 8) { cnt4 = 0; } + + if(!cnt0) { // store every 64th sample in the array[0] + sampleArray[LEFTCHANNEL][0][cnt1] = abs(sample[LEFTCHANNEL] >> 7); + sampleArray[RIGHTCHANNEL][0][cnt1] = abs(sample[RIGHTCHANNEL] >> 7); + } + if(!cnt1) { // store argest from 64 * 8 samples in the array[1] + sampleArray[LEFTCHANNEL][1][cnt2] = largest(sampleArray[LEFTCHANNEL][0]); + sampleArray[RIGHTCHANNEL][1][cnt2] = largest(sampleArray[RIGHTCHANNEL][0]); + } + if(!cnt2) { // store avg from 64 * 8 * 8 samples in the array[2] + sampleArray[LEFTCHANNEL][2][cnt3] = largest(sampleArray[LEFTCHANNEL][1]); + sampleArray[RIGHTCHANNEL][2][cnt3] = largest(sampleArray[RIGHTCHANNEL][1]); + } + if(!cnt3) { // store avg from 64 * 8 * 8 * 8 samples in the array[3] + sampleArray[LEFTCHANNEL][3][cnt4] = avg(sampleArray[LEFTCHANNEL][2]); + sampleArray[RIGHTCHANNEL][3][cnt4] = avg(sampleArray[RIGHTCHANNEL][2]); + } + if(f_vu) { + f_vu = false; + vuLeft = avg(sampleArray[LEFTCHANNEL][3]); + if(vuLeft>config.vuThreshold) config.vuThreshold = vuLeft; + vuRight = avg(sampleArray[RIGHTCHANNEL][3]); + if(vuRight>config.vuThreshold) config.vuThreshold = vuRight; + } + cnt1++; +} + +uint16_t Audio::get_VUlevel(uint16_t dimension){ + if(!config.store.vumeter || config.vuThreshold==0) return 0; + uint8_t L = map(vuLeft, config.vuThreshold, 0, 0, dimension); + uint8_t R = map(vuRight, config.vuThreshold, 0, 0, dimension); + return (L << 8) | R; +} //--------------------------------------------------------------------------------------------------------------------- void Audio::loop() { if(!m_f_running) { + vuLeft=0; vuRight=0; vTaskDelay(2); return; } @@ -4563,7 +4610,7 @@ bool Audio::playSample(int16_t sample[2]) { sample = IIR_filterChain1(sample); sample = IIR_filterChain2(sample); //------------------------------------------- - + _computeVUlevel(sample); uint32_t s32 = Gain(sample); // vosample2lume; if(m_f_internalDAC) { diff --git a/yoRadio/src/audioI2S/AudioEx.h b/yoRadio/src/audioI2S/AudioEx.h index a126759..c25184c 100644 --- a/yoRadio/src/audioI2S/AudioEx.h +++ b/yoRadio/src/audioI2S/AudioEx.h @@ -35,6 +35,7 @@ #ifndef AUDIOBUFFER_MULTIPLIER2 #define AUDIOBUFFER_MULTIPLIER2 8 #endif + #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) #include "hal/gpio_ll.h" #endif @@ -211,7 +212,8 @@ public: /* VU METER */ void setVUmeter() {}; void getVUlevel() {}; - uint8_t vuLeft, vuRight; + uint16_t get_VUlevel(uint16_t dimension); + bool eofHeader; esp_err_t i2s_mclk_pin_select(const uint8_t pin); uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer @@ -284,7 +286,7 @@ private: inline uint32_t streamavail(){ return _client ? _client->available() : 0;} void IIR_calculateCoefficients(int8_t G1, int8_t G2, int8_t G3); bool ts_parsePacket(uint8_t* packet, uint8_t* packetStart, uint8_t* packetLength); - + void _computeVUlevel(int16_t sample[2]); // implement several function with respect to the index of string void trim(char *s) { //fb trim in place @@ -561,6 +563,7 @@ private: int16_t m_pidOfAAC; uint8_t m_packetBuff[m_tsPacketSize]; int16_t m_pesDataLength = 0; + uint16_t vuLeft, vuRight; }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp index 2a81273..bce51c5 100644 --- a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp +++ b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp @@ -1658,16 +1658,26 @@ void Audio::setVUmeter() { * * \warning This feature is only available with patches that support VU meter. */ -void Audio::getVUlevel() { +const uint8_t everyn = 4; +void Audio::computeVUlevel() { if(!VS_PATCH_ENABLE) return; - if(!_vuInitalized) return; + static uint8_t cc = 0; + cc++; + if(!_vuInitalized || !config.store.vumeter || cc!=everyn) return; + if(cc==everyn) cc=0; int16_t reg = read_register(SCI_AICTRL3); - uint8_t rl = map((uint8_t)reg, 85, 92, 0, 255); - uint8_t rr = map((uint8_t)(reg >> 8), 85, 92, 0, 255); - //if(rl>30 || !isRunning()) vuLeft = rl; - //if(rr>30 || !isRunning()) vuRight = rr; - vuLeft = rl; - vuRight = rr; + vuLeft = map((uint8_t)(reg & 0x00FF), 85, 92, 0, 255); + vuRight = map((uint8_t)(reg >> 8), 85, 92, 0, 255); + if(vuLeft>config.vuThreshold) config.vuThreshold = vuLeft; + if(vuRight>config.vuThreshold) config.vuThreshold=vuRight; +} + +uint16_t Audio::get_VUlevel(uint16_t dimension){ + if(!VS_PATCH_ENABLE) return 0; + if(!_vuInitalized || !config.store.vumeter || config.vuThreshold==0) return 0; + uint8_t L = map(vuLeft, config.vuThreshold, 0, 0, dimension); + uint8_t R = map(vuRight, config.vuThreshold, 0, 0, dimension); + return (L << 8) | R; } //--------------------------------------------------------------------------------------------------------------------- void Audio::setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl){ diff --git a/yoRadio/src/audioVS1053/audioVS1053Ex.h b/yoRadio/src/audioVS1053/audioVS1053Ex.h index 52311cc..9640c3e 100644 --- a/yoRadio/src/audioVS1053/audioVS1053Ex.h +++ b/yoRadio/src/audioVS1053/audioVS1053Ex.h @@ -236,6 +236,7 @@ private: const char volumetable[22]={ 0,50,60,65,70,75,80,82,84,86, 88,90,91,92,93,94,95,96,97,98,99,100}; //22 elements + uint8_t vuLeft, vuRight; protected: inline void DCS_HIGH() {(dcs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << (dcs_pin - 32) : GPIO.out_w1ts = 1 << dcs_pin;} inline void DCS_LOW() {(dcs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << (dcs_pin - 32) : GPIO.out_w1tc = 1 << dcs_pin;} @@ -324,8 +325,8 @@ public: void forceMono(bool m) {} // TODO /* VU METER */ void setVUmeter(); - void getVUlevel(); - uint8_t vuLeft, vuRight; + uint16_t get_VUlevel(uint16_t dimension); + void computeVUlevel(); bool eofHeader; // implement several function with respect to the index of string bool startsWith (const char* base, const char* str) { return (strstr(base, str) - base) == 0;} diff --git a/yoRadio/src/core/config.cpp b/yoRadio/src/core/config.cpp index 2ccd550..91a8c31 100644 --- a/yoRadio/src/core/config.cpp +++ b/yoRadio/src/core/config.cpp @@ -407,6 +407,7 @@ uint8_t Config::setLastSSID(uint8_t val) { } void Config::setTitle(const char* title) { + vuThreshold = 0; memset(config.station.title, 0, BUFLEN); strlcpy(config.station.title, title, BUFLEN); u8fix(config.station.title); diff --git a/yoRadio/src/core/config.h b/yoRadio/src/core/config.h index c38696c..d965767 100644 --- a/yoRadio/src/core/config.h +++ b/yoRadio/src/core/config.h @@ -174,6 +174,7 @@ class Config { uint16_t sleepfor; uint32_t sdResumePos; bool emptyFS; + uint16_t vuThreshold; public: Config() {}; //void save(); diff --git a/yoRadio/src/core/display.cpp b/yoRadio/src/core/display.cpp index 8c3e31f..0737a48 100644 --- a/yoRadio/src/core/display.cpp +++ b/yoRadio/src/core/display.cpp @@ -452,6 +452,9 @@ void Display::loop() { } } dsp.loop(); + #if I2S_DOUT==255 + player.computeVUlevel(); + #endif } void Display::_setRSSI(int rssi) { diff --git a/yoRadio/src/core/netserver.cpp b/yoRadio/src/core/netserver.cpp index 91c788b..ce0a47a 100644 --- a/yoRadio/src/core/netserver.cpp +++ b/yoRadio/src/core/netserver.cpp @@ -287,11 +287,12 @@ void NetServer::processQueue(){ return; break; } - case GETSYSTEM: sprintf (wsbuf, "{\"sst\":%d,\"aif\":%d,\"vu\":%d,\"softr\":%d}", + case GETSYSTEM: sprintf (wsbuf, "{\"sst\":%d,\"aif\":%d,\"vu\":%d,\"softr\":%d,\"vut\":%d}", config.store.smartstart != 2, config.store.audioinfo, config.store.vumeter, - config.store.softapdelay); + config.store.softapdelay, + config.vuThreshold); break; case GETSCREEN: sprintf (wsbuf, "{\"flip\":%d,\"inv\":%d,\"nump\":%d,\"tsf\":%d,\"tsd\":%d,\"dspon\":%d,\"br\":%d,\"con\":%d}", config.store.flipscreen, diff --git a/yoRadio/src/core/network.cpp b/yoRadio/src/core/network.cpp index 4763066..a8b60fe 100644 --- a/yoRadio/src/core/network.cpp +++ b/yoRadio/src/core/network.cpp @@ -72,6 +72,7 @@ void ticks() { #ifdef USE_SD if(display.mode()!=SDCHANGE) player.sendCommand({PR_CHECKSD, 0}); #endif + player.sendCommand({PR_VUTONUS, 0}); } } diff --git a/yoRadio/src/core/options.h b/yoRadio/src/core/options.h index 51df279..d9fe1da 100644 --- a/yoRadio/src/core/options.h +++ b/yoRadio/src/core/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define YOVERSION "0.9.380" +#define YOVERSION "0.9.390" /******************************************************* DO NOT EDIT THIS FILE. @@ -467,12 +467,16 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti #define L10N_LANGUAGE EN #endif -#ifndef VSPI - #define VSPI 3 -#endif -#ifndef HSPI - #define HSPI 1 +#ifdef VSPI +#define VOOPSENb VSPI +#else +#define VOOPSENb 3 #endif +#ifdef HSPI +#define HOOPSENb HSPI +#else +#define HOOPSENb 2 +#endif #endif diff --git a/yoRadio/src/core/player.cpp b/yoRadio/src/core/player.cpp index 8761ffb..b2e8021 100644 --- a/yoRadio/src/core/player.cpp +++ b/yoRadio/src/core/player.cpp @@ -157,6 +157,8 @@ void Player::loop() { break; } #endif + case PR_VUTONUS: + if(config.vuThreshold>10) config.vuThreshold -=10; default: break; } } @@ -186,6 +188,7 @@ void Player::_play(uint16_t stationId) { setError(""); remoteStationName = false; config.setDspOn(1); + config.vuThreshold = 0; //display.putRequest(PSTOP); if(config.getMode()!=PM_SDCARD) { display.putRequest(PSTOP); diff --git a/yoRadio/src/core/player.h b/yoRadio/src/core/player.h index 26e2ced..a10e6a9 100644 --- a/yoRadio/src/core/player.h +++ b/yoRadio/src/core/player.h @@ -19,7 +19,7 @@ #define PLERR_LN 64 #define SET_PLAY_ERROR(...) {char buff[512 + 64]; sprintf(buff,__VA_ARGS__); setError(buff);} -enum playerRequestType_e : uint8_t { PR_PLAY = 1, PR_STOP = 2, PR_PREV = 3, PR_NEXT = 4, PR_VOL = 5, PR_CHECKSD = 6 }; +enum playerRequestType_e : uint8_t { PR_PLAY = 1, PR_STOP = 2, PR_PREV = 3, PR_NEXT = 4, PR_VOL = 5, PR_CHECKSD = 6, PR_VUTONUS = 7 }; struct playerRequestParams_t { playerRequestType_e type; diff --git a/yoRadio/src/displays/nextion.cpp b/yoRadio/src/displays/nextion.cpp index adab5d0..08bc409 100644 --- a/yoRadio/src/displays/nextion.cpp +++ b/yoRadio/src/displays/nextion.cpp @@ -294,9 +294,15 @@ void Nextion::drawVU(){ //if(mode!=PLAYER) return; if(mode!=PLAYER && mode!=VOL) return; static uint8_t measL, measR; - player.getVUlevel(); - uint8_t L = map(player.vuLeft, 0, 255, 0, 100); - uint8_t R = map(player.vuRight, 0, 255, 0, 100); + //player.getVUlevel(); + + uint16_t vulevel = player.get_VUlevel((uint16_t)100); + + uint8_t L = (vulevel >> 8) & 0xFF; + uint8_t R = vulevel & 0xFF; + + //uint8_t L = map(player.vuLeft, 0, 255, 0, 100); + //uint8_t R = map(player.vuRight, 0, 255, 0, 100); if(player.isRunning()){ measL=(L<=measL)?measL-5:L; measR=(R<=measR)?measR-5:R; diff --git a/yoRadio/src/displays/widgets/widgets.cpp b/yoRadio/src/displays/widgets/widgets.cpp index 4e5fc9e..601e93b 100644 --- a/yoRadio/src/displays/widgets/widgets.cpp +++ b/yoRadio/src/displays/widgets/widgets.cpp @@ -284,21 +284,25 @@ void VuWidget::init(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor _canvas = new Canvas(_bands.width * 2 + _bands.space, _bands.height); } + void VuWidget::_draw(){ if(!_active || _locked) return; #if !defined(USE_NEXTION) && I2S_DOUT==255 - static uint8_t cc = 0; +/* static uint8_t cc = 0; cc++; if(cc>0){ player.getVUlevel(); cc=0; - } + }*/ #endif static uint16_t measL, measR; uint16_t bandColor; uint16_t dimension = _config.align?_bands.width:_bands.height; - uint8_t L = map(player.vuLeft, 255, 0, 0, dimension); - uint8_t R = map(player.vuRight, 255, 0, 0, dimension); + uint16_t vulevel = player.get_VUlevel(dimension); + + uint8_t L = (vulevel >> 8) & 0xFF; + uint8_t R = vulevel & 0xFF; + bool played = player.isRunning(); if(played){ measL=(L>=measL)?measL + _bands.fadespeed:L; diff --git a/yoRadio/src/main.cpp b/yoRadio/src/main.cpp index 728abc4..eea54b1 100644 --- a/yoRadio/src/main.cpp +++ b/yoRadio/src/main.cpp @@ -11,7 +11,7 @@ #include "core/optionschecker.h" #if DSP_HSPI || TS_HSPI || VS_HSPI -SPIClass SPI2(HSPI); +SPIClass SPI2(HOOPSENb); #endif extern __attribute__((weak)) void yoradio_on_setup();