Unverified Commit 1a9a252e authored by Wolle's avatar Wolle Committed by GitHub

Merge pull request #571 from schreibfaul1/volume-curve

Volume curve
parents a4c3529c 8b41160e
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* *
* Created on: Oct 26.2018 * Created on: Oct 26.2018
* *
* Version 3.0.5 * Version 3.0.6
* Updated on: Aug 04.2023 * Updated on: Aug 05.2023
* Author: Wolle (schreibfaul1) * Author: Wolle (schreibfaul1)
* *
*/ */
...@@ -244,6 +244,8 @@ Audio::Audio(bool internalDAC /* = false */, uint8_t channelEnabled /* = I2S_DAC ...@@ -244,6 +244,8 @@ Audio::Audio(bool internalDAC /* = false */, uint8_t channelEnabled /* = I2S_DAC
m_filter[i].b1 = 0; m_filter[i].b1 = 0;
m_filter[i].b2 = 0; m_filter[i].b2 = 0;
} }
computeLimit(); // first init, vol = 21, vol_steps = 21
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void Audio::setBufsize(int rambuf_sz, int psrambuf_sz) { void Audio::setBufsize(int rambuf_sz, int psrambuf_sz) {
...@@ -4357,11 +4359,7 @@ bool Audio::setAudioPlayPosition(uint16_t sec){ ...@@ -4357,11 +4359,7 @@ bool Audio::setAudioPlayPosition(uint16_t sec){
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void Audio::setVolumeSteps(uint8_t steps) { void Audio::setVolumeSteps(uint8_t steps) {
m_vol_steps = steps; m_vol_steps = steps;
if (steps < 1) if (steps < 1) m_vol_steps = 64; /* avoid div-by-zero :-) */
m_vol_step_div = 64; /* avoid div-by-zero :-) */
else
m_vol_step_div = steps * steps;
// log_i("m_vol_step_div: %d", m_vol_step_div);
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
uint8_t Audio::maxVolume() { uint8_t Audio::maxVolume() {
...@@ -4633,38 +4631,67 @@ void Audio::setBalance(int8_t bal){ // bal -16...16 ...@@ -4633,38 +4631,67 @@ void Audio::setBalance(int8_t bal){ // bal -16...16
if(bal < -16) bal = -16; if(bal < -16) bal = -16;
if(bal > 16) bal = 16; if(bal > 16) bal = 16;
m_balance = bal; m_balance = bal;
computeLimit();
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void Audio::setVolume(uint8_t vol) { void Audio::setVolume(uint8_t vol, uint8_t curve) { // curve 0: default, curve 1: flat at the beginning
if (vol > m_vol_steps) vol = m_vol_steps; if (vol > m_vol_steps) m_vol = m_vol_steps;
m_vol = vol * vol; else m_vol = vol;
return;
if (curve > 1) m_curve = 1;
else m_curve = curve;
computeLimit();
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
uint8_t Audio::getVolume() { uint8_t Audio::getVolume() {
uint8_t vol = sqrt(m_vol); return m_vol;
return vol;
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
uint8_t Audio::getI2sPort() { uint8_t Audio::getI2sPort() {
return m_i2s_num; return m_i2s_num;
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
int32_t Audio::Gain(int16_t s[2]) { void Audio::computeLimit(){ // is calculated when the volume or balance changes
int32_t v[2]; double l = 1, r = 1, v = 1; // assume 100%
int32_t l = m_vol, r = m_vol;
/* balance is left -16...+16 right */ /* balance is left -16...+16 right */
/* TODO: logarithmic scaling of balance, too? */ /* TODO: logarithmic scaling of balance, too? */
if(m_balance < 0){ if(m_balance < 0){
r -= (int32_t)m_vol * abs(m_balance) / 16; r -= (double)abs(m_balance) / 16;
} else if(m_balance > 0){ } else if(m_balance > 0){
l -= (int32_t)m_vol * abs(m_balance) / 16; l -= (double)abs(m_balance) / 16;
} }
switch(m_curve){
case 0:
v = (double)pow(m_vol, 2) / pow(m_vol_steps, 2); // square (default)
break;
case 1: // logarithmic
double log1 = log(1);
if (m_vol>0) {
v = m_vol * ((std::exp( log1 + (m_vol-1) * (std::log(m_vol_steps)-log1) / (m_vol_steps-1)))/m_vol_steps) / m_vol_steps;
}
else {
v = 0;
}
break;
}
m_limit_left = l * v;
m_limit_right = r * v;
// log_i("m_limit_left %f, m_limit_right %f ",m_limit_left, m_limit_right);
}
//---------------------------------------------------------------------------------------------------------------------
int32_t Audio::Gain(int16_t s[2]) {
int32_t v[2];
/* important: these multiplications must all be signed ints, or the result will be invalid */ /* important: these multiplications must all be signed ints, or the result will be invalid */
v[LEFTCHANNEL] = (s[LEFTCHANNEL] * l) / m_vol_step_div; v[LEFTCHANNEL] = s[LEFTCHANNEL] * m_limit_left;
v[RIGHTCHANNEL]= (s[RIGHTCHANNEL] * r) / m_vol_step_div; v[RIGHTCHANNEL]= s[RIGHTCHANNEL] * m_limit_right;
return (v[LEFTCHANNEL] << 16) | (v[RIGHTCHANNEL] & 0xffff); return (v[LEFTCHANNEL] << 16) | (v[RIGHTCHANNEL] & 0xffff);
} }
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* *
* Created on: Oct 28,2018 * Created on: Oct 28,2018
* *
* Version 3.0.5 * Version 3.0.6
* Updated on: Aug 04.2023 * Updated on: Aug 05.2023
* Author: Wolle (schreibfaul1) * Author: Wolle (schreibfaul1)
*/ */
...@@ -185,7 +185,7 @@ public: ...@@ -185,7 +185,7 @@ public:
void forceMono(bool m); void forceMono(bool m);
void setBalance(int8_t bal = 0); void setBalance(int8_t bal = 0);
void setVolumeSteps(uint8_t steps); void setVolumeSteps(uint8_t steps);
void setVolume(uint8_t vol); void setVolume(uint8_t vol, uint8_t curve = 0);
uint8_t getVolume(); uint8_t getVolume();
uint8_t maxVolume(); uint8_t maxVolume();
uint8_t getI2sPort(); uint8_t getI2sPort();
...@@ -256,6 +256,7 @@ private: ...@@ -256,6 +256,7 @@ private:
bool playChunk(); bool playChunk();
bool playSample(int16_t sample[2]); bool playSample(int16_t sample[2]);
void computeVUlevel(int16_t sample[2]); void computeVUlevel(int16_t sample[2]);
void computeLimit();
int32_t Gain(int16_t s[2]); int32_t Gain(int16_t s[2]);
void showstreamtitle(const char* ml); void showstreamtitle(const char* ml);
bool parseContentType(char* ct); bool parseContentType(char* ct);
...@@ -265,8 +266,8 @@ private: ...@@ -265,8 +266,8 @@ private:
esp_err_t I2Sstop(uint8_t i2s_num); esp_err_t I2Sstop(uint8_t i2s_num);
void urlencode(char* buff, uint16_t buffLen, bool spacesOnly = false); void urlencode(char* buff, uint16_t buffLen, bool spacesOnly = false);
int16_t* IIR_filterChain0(int16_t iir_in[2], bool clear = false); int16_t* IIR_filterChain0(int16_t iir_in[2], bool clear = false);
int16_t* IIR_filterChain1(int16_t* iir_in, bool clear = false); int16_t* IIR_filterChain1(int16_t iir_in[2], bool clear = false);
int16_t* IIR_filterChain2(int16_t* iir_in, bool clear = false); int16_t* IIR_filterChain2(int16_t iir_in[2], bool clear = false);
inline void setDatamode(uint8_t dm){m_datamode=dm;} inline void setDatamode(uint8_t dm){m_datamode=dm;}
inline uint8_t getDatamode(){return m_datamode;} inline uint8_t getDatamode(){return m_datamode;}
inline uint32_t streamavail(){ return _client ? _client->available() : 0;} inline uint32_t streamavail(){ return _client ? _client->available() : 0;}
...@@ -509,9 +510,11 @@ private: ...@@ -509,9 +510,11 @@ private:
uint32_t m_metacount = 0; // counts down bytes between metadata uint32_t m_metacount = 0; // counts down bytes between metadata
int m_controlCounter = 0; // Status within readID3data() and readWaveHeader() int m_controlCounter = 0; // Status within readID3data() and readWaveHeader()
int8_t m_balance = 0; // -16 (mute left) ... +16 (mute right) int8_t m_balance = 0; // -16 (mute left) ... +16 (mute right)
uint16_t m_vol=64; // volume uint16_t m_vol = 21; // volume
uint8_t m_vol_steps = 21; // default uint8_t m_vol_steps = 21; // default
int32_t m_vol_step_div = 21 * 21; // double m_limit_left = 0; // limiter 0 ... 1, left channel
double m_limit_right = 0; // limiter 0 ... 1, right channel
uint8_t m_curve = 0; // volume characteristic
uint8_t m_bitsPerSample = 16; // bitsPerSample uint8_t m_bitsPerSample = 16; // bitsPerSample
uint8_t m_channels = 2; uint8_t m_channels = 2;
uint8_t m_i2s_num = I2S_NUM_0; // I2S_NUM_0 or I2S_NUM_1 uint8_t m_i2s_num = I2S_NUM_0; // I2S_NUM_0 or I2S_NUM_1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment