equalizer.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Squeezelite for esp32
  3. *
  4. * (c) Philippe G. 2020, philippe_44@outlook.com
  5. *
  6. * This software is released under the MIT License.
  7. * https://opensource.org/licenses/MIT
  8. *
  9. */
  10. #include "math.h"
  11. #include "platform_config.h"
  12. #include "squeezelite.h"
  13. #include "equalizer.h"
  14. #include "esp_equalizer.h"
  15. #define EQ_BANDS 10
  16. static log_level loglevel = lINFO;
  17. static EXT_RAM_ATTR struct {
  18. void *handle;
  19. float loudness, volume;
  20. uint32_t samplerate;
  21. float gain[EQ_BANDS], loudness_gain[EQ_BANDS];
  22. bool update;
  23. } equalizer;
  24. #define POLYNOME_COUNT 6
  25. static const float loudness_envelope_coefficients[EQ_BANDS][POLYNOME_COUNT] = {
  26. {5.5169301499257067e+001, 6.3671410796029004e-001,
  27. -4.2663226432095233e-002, 8.1063072336581246e-004,
  28. -7.3621858933917722e-006, 2.5349489594339575e-008},
  29. {3.7716143859944118e+001, 1.2355293276538579e+000,
  30. -6.6435374582217863e-002, 1.2976763440259382e-003,
  31. -1.1978732496353172e-005, 4.1664114634622593e-008},
  32. {2.5103632377146837e+001, 1.3259150615414637e+000,
  33. -6.6332442135695099e-002, 1.2845279812261677e-003,
  34. -1.1799885217545631e-005, 4.0925911584040685e-008},
  35. {1.3159168212144563e+001, 8.8149357628440639e-001,
  36. -4.0384121097225931e-002, 7.3843501027501322e-004,
  37. -6.5508794453097008e-006, 2.2221997141120518e-008},
  38. {5.1337853800151700e+000, 4.0817077967582394e-001,
  39. -1.4107826528626457e-002, 1.5251066311713760e-004,
  40. -3.6689819583740298e-007, -2.0390798774727989e-009},
  41. {3.1432364156464315e-001, 9.1260548140023004e-002,
  42. -3.5012124633183438e-004, -8.6023911664606992e-005,
  43. 1.6785606828245921e-006, -8.8269731094371646e-009},
  44. {-4.0965062397075833e+000, 1.3667010948271402e-001,
  45. 2.4775896786988390e-004, -9.6620399661858641e-005,
  46. 1.7733690952379155e-006, -9.1583104942496635e-009},
  47. {-9.0275786029994176e+000, 2.6226938845184250e-001,
  48. -6.5777547972402156e-003, 1.0045957188977551e-004,
  49. -7.8851000325128971e-007, 2.4639885209682384e-009},
  50. {-4.4275018199195815e+000, 4.5399572638241725e-001,
  51. -2.4034902766833462e-002, 5.9828953622534668e-004,
  52. -6.2893971217140864e-006, 2.3133296592719627e-008},
  53. {1.4243299202697818e+001, 3.6984458807056630e-001,
  54. -3.0413994109395680e-002, 7.6700105080386904e-004,
  55. -8.2777185209388079e-006, 3.1352890650784970e-008} };
  56. /****************************************************************************************
  57. * calculate loudness gains
  58. */
  59. static void calculate_loudness(void) {
  60. char trace[EQ_BANDS * 5 + 1];
  61. size_t n = 0;
  62. for (int i = 0; i < EQ_BANDS; i++) {
  63. for (int j = 0; j < POLYNOME_COUNT && equalizer.loudness != 0; j++) {
  64. equalizer.loudness_gain[i] +=
  65. loudness_envelope_coefficients[i][j] * pow(equalizer.volume, j);
  66. }
  67. equalizer.loudness_gain[i] *= equalizer.loudness / 2;
  68. n += sprintf(trace + n, "%.2g%c", equalizer.loudness_gain[i], i < EQ_BANDS ? ',' : '\0');
  69. }
  70. LOG_INFO("loudness %s", trace);
  71. }
  72. /****************************************************************************************
  73. * initialize equalizer
  74. */
  75. void equalizer_init(void) {
  76. // handle equalizer
  77. char *config = config_alloc_get(NVS_TYPE_STR, "equalizer");
  78. char *p = strtok(config, ", !");
  79. for (int i = 0; p && i < EQ_BANDS; i++) {
  80. equalizer.gain[i] = atoi(p);
  81. p = strtok(NULL, ", :");
  82. }
  83. free(config);
  84. // handle loudness
  85. config = config_alloc_get(NVS_TYPE_STR, "loudness");
  86. equalizer.loudness = atof(config) / 10.0;
  87. free(config);
  88. }
  89. /****************************************************************************************
  90. * close equalizer
  91. */
  92. void equalizer_close(void) {
  93. if (equalizer.handle) {
  94. esp_equalizer_uninit(equalizer.handle);
  95. equalizer.handle = NULL;
  96. }
  97. }
  98. /****************************************************************************************
  99. * change sample rate
  100. */
  101. void equalizer_set_samplerate(uint32_t samplerate) {
  102. #if BYTES_PER_FRAME == 4
  103. if (equalizer.samplerate != samplerate) equalizer_close();
  104. equalizer.samplerate = samplerate;
  105. equalizer.update = true;
  106. LOG_INFO("equalizer sample rate %u", samplerate);
  107. #else
  108. LOG_INFO("no equalizer with 32 bits samples");
  109. #endif
  110. }
  111. /****************************************************************************************
  112. * get volume update and recalculate loudness according to
  113. */
  114. void equalizer_set_volume(unsigned left, unsigned right) {
  115. #if BYTES_PER_FRAME == 4
  116. float volume = (left + right) / 2;
  117. // do classic dB conversion and scale it 0..100
  118. if (volume) volume = log2(volume);
  119. volume = volume / 16.0 * 100.0;
  120. // LMS has the bad habit to send multiple volume commands
  121. if (volume != equalizer.volume && equalizer.loudness) {
  122. equalizer.volume = volume;
  123. calculate_loudness();
  124. equalizer.update = true;
  125. }
  126. #endif
  127. }
  128. /****************************************************************************************
  129. * change gains from LMS
  130. */
  131. void equalizer_set_gain(int8_t *gain) {
  132. #if BYTES_PER_FRAME == 4
  133. static uint8_t last_gain[EQ_BANDS] = { };
  134. bool eq_update = false;
  135. char config[EQ_BANDS * 4 + 1] = { };
  136. int n = 0;
  137. for (int i = 0; i < EQ_BANDS; i++) {
  138. equalizer.gain[i] = gain[i];
  139. n += sprintf(config + n, "%d,", gain[i]);
  140. if (gain[i] != last_gain[i])
  141. {
  142. eq_update = true;
  143. }
  144. last_gain[i] = gain[i];
  145. }
  146. config[n-1] = '\0';
  147. config_set_value(NVS_TYPE_STR, "equalizer", config);
  148. //"or" in this value in case equalizer.update is set for another reason
  149. equalizer.update |= eq_update;
  150. LOG_INFO("equalizer gain %s", config);
  151. #else
  152. LOG_INFO("no equalizer with 32 bits samples");
  153. #endif
  154. }
  155. /****************************************************************************************
  156. * change loudness from LMS
  157. */
  158. void equalizer_set_loudness(uint8_t loudness) {
  159. #if BYTES_PER_FRAME == 4
  160. char p[4];
  161. itoa(loudness, p, 10);
  162. config_set_value(NVS_TYPE_STR, "loudness", p);
  163. // update loudness gains as a factor of loudness and volume
  164. if (equalizer.loudness != loudness / 10.0) {
  165. equalizer.loudness = loudness / 10.0;
  166. calculate_loudness();
  167. equalizer.update = true;
  168. }
  169. LOG_INFO("loudness %u", (unsigned) loudness);
  170. #else
  171. LOG_INFO("no equalizer with 32 bits samples");
  172. #endif
  173. }
  174. /****************************************************************************************
  175. * process equalizer
  176. */
  177. void equalizer_process(uint8_t *buf, uint32_t bytes) {
  178. #if BYTES_PER_FRAME == 4
  179. // don't want to process with output locked, so take the small risk to miss one parametric update
  180. if (equalizer.update) {
  181. equalizer.update = false;
  182. if (equalizer.samplerate != 11025 && equalizer.samplerate != 22050 && equalizer.samplerate != 44100 && equalizer.samplerate != 48000) {
  183. LOG_WARN("equalizer only supports 11025, 22050, 44100 and 48000 sample rates, not %u", equalizer.samplerate);
  184. return;
  185. }
  186. if (!equalizer.handle && ((equalizer.handle = esp_equalizer_init(2, equalizer.samplerate, EQ_BANDS, 0)) == NULL)) {
  187. LOG_WARN("can't init equalizer");
  188. return;
  189. }
  190. bool active = false;
  191. for (int i = 0; i < EQ_BANDS; i++) {
  192. float gain = equalizer.gain[i] + equalizer.loudness_gain[i];
  193. esp_equalizer_set_band_value(equalizer.handle, gain, i, 0);
  194. esp_equalizer_set_band_value(equalizer.handle, gain, i, 1);
  195. active |= gain != 0;
  196. }
  197. // at the end do not activate equalizer if all gain are 0
  198. if (!active) equalizer_close();
  199. LOG_INFO("equalizer %s", active ? "actived" : "deactivated");
  200. }
  201. if (equalizer.handle) {
  202. esp_equalizer_process(equalizer.handle, buf, bytes, equalizer.samplerate, 2);
  203. }
  204. #endif
  205. }