epr.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /* Copyright 2014,2015 Tobias Platen */
  2. /* This file is part of Sekai.
  3. Sekai is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. Sekai is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with Sekai. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include "sekai/epr.h"
  15. #include <math.h>
  16. #include <stdlib.h>
  17. #include "sekai/common.h"
  18. #include <assert.h>
  19. static int double_compare(const void *a, const void *b) {
  20. double *x = (double *)b;
  21. double *y = (double *)a;
  22. if (*x == *y) return 0;
  23. if (*x > *y)
  24. return 1;
  25. else
  26. return -1;
  27. }
  28. void calc_slope(double *slope, double *sourcedb, double *f, double gaindb,
  29. double slopedepthdb, int count) {
  30. for (int i = 0; i < count; i++) {
  31. slope[i] = log((sourcedb[i] - gaindb) / slopedepthdb + 1) / f[i];
  32. if (isnan(slope[i]) && i > 0) slope[i] = slope[i - 1];
  33. }
  34. qsort((void *)slope, count, sizeof(double), double_compare);
  35. }
  36. void EprSourceEstimate(double *spectrogram, int fft_size, int fs, double f0,
  37. EprSourceParams *params) {
  38. if (f0 < 50) {
  39. params->slope = 0;
  40. params->gaindb = 0;
  41. params->slopedepthdb = 0;
  42. return;
  43. }
  44. double min = 0;
  45. int maxharm = fs / f0 - 2;
  46. double *sourcedb = new double[maxharm];
  47. double *fharm = new double[maxharm];
  48. double *slope = new double[maxharm];
  49. for (int i = 1; i < fft_size / 2 - 1; i++) {
  50. double current = TWENTY_OVER_LOG10 * log(spectrogram[i]);
  51. if (current < min) min = current;
  52. }
  53. for (int i = 0; i < maxharm; i++) {
  54. double frq = (i + 1) * f0;
  55. int bin = frq * fft_size / fs;
  56. sourcedb[i] = TWENTY_OVER_LOG10 * log(spectrogram[bin]);
  57. fharm[i] = frq;
  58. }
  59. double gaindb = sourcedb[0];
  60. double slopedepthdb = -min + gaindb;
  61. calc_slope(slope, sourcedb, fharm, gaindb, slopedepthdb, maxharm);
  62. params->gaindb = gaindb;
  63. params->slopedepthdb = slopedepthdb;
  64. int startindex = -1;
  65. for (int i = 0; i < maxharm; i++) {
  66. // printf("slope[%i]: %f\n",i,slope[i]);
  67. if (startindex == -1 && slope[i] < 0) startindex = i;
  68. }
  69. int slope_index = (maxharm - startindex) / 2 + startindex;
  70. params->slope = slope[slope_index];
  71. delete[] sourcedb;
  72. delete[] fharm;
  73. delete[] slope;
  74. }
  75. inline int sgn(double x) {
  76. if (x == 0)
  77. return 0;
  78. else
  79. return (x > 0) ? 1 : -1;
  80. }
  81. int findMaxima(double *tmp, int fft_size, int fs, EprResonance *res, int nres) {
  82. int sign = 0;
  83. int oldsign = 0;
  84. int i = 0;
  85. for (int j = 2; j < fft_size / 2 - 8; j++) {
  86. sign = sgn(tmp[j] - tmp[j + 1]);
  87. if (sign != oldsign) {
  88. double a = tmp[j];
  89. double f = j * fs / fft_size;
  90. if (a > tmp[j - 1] && a > tmp[j - 2] && a > tmp[j + 1] &&
  91. a > tmp[j + 2] && i < nres) {
  92. res[i].gain_db = tmp[j - 1]; // select correct bin
  93. res[i].f = f;
  94. i++;
  95. }
  96. }
  97. }
  98. return i;
  99. }
  100. void getBandwidth(double *tmp, int fft_size, int fs, EprResonance *res) {
  101. double freq = res->f;
  102. double gain = res->gain_db;
  103. int bin = freq * fft_size / fs;
  104. // printf("bin %i\n",bin);
  105. double freq_left = 0;
  106. double freq_right = 0;
  107. for (int i = 0; i < 40; i++) {
  108. int index = i + bin;
  109. if (index > 0 && index < fft_size / 2 - 8) {
  110. double freq2 = i * fs / fft_size;
  111. double gaindrop = gain - tmp[index];
  112. // printf("gaindrop R %f %f\n",freq2,gaindrop);
  113. freq_right = freq2;
  114. if (gaindrop > 3) break;
  115. }
  116. }
  117. for (int i = 0; i < 40; i++) {
  118. int index = bin - i;
  119. if (index > 0 && index < fft_size / 2 - 8) {
  120. double freq2 = i * fs / fft_size;
  121. double gaindrop = gain - tmp[index];
  122. // printf("gaindrop L %f %f\n",freq2,gaindrop);
  123. if (gaindrop > 3) break;
  124. freq_left = freq2;
  125. }
  126. }
  127. double bw = sqrt(freq_left * freq_right);
  128. // FIXME one of both is zero: not found
  129. res->bw = bw;
  130. EprResonanceUpdate(res, fs);
  131. }
  132. int EprVocalTractEstimate(double *spectrogram, int fft_size, int fs, double f0,
  133. EprSourceParams *params, double *tmp,
  134. EprResonance *res, int nres) {
  135. for (int i = 0; i < fft_size / 2; i++) {
  136. double f = fs * i / fft_size;
  137. double spect = TWENTY_OVER_LOG10 * log(spectrogram[i]);
  138. double source = params->gaindb +
  139. params->slopedepthdb * (pow(M_E, params->slope * f) - 1);
  140. tmp[i] = spect - source;
  141. }
  142. int count = findMaxima(tmp, fft_size, fs, res, nres);
  143. for (int i = 0; i < count; i++) {
  144. getBandwidth(tmp, fft_size, fs, &res[i]);
  145. }
  146. for (int i = 0; i < count; i++) {
  147. EprResonanceUpdate(&res[i], fs);
  148. }
  149. for (int i = 0; i < fft_size / 2 + 1; i++) {
  150. double f = i * fs * 1.0 / fft_size;
  151. double db = TWENTY_OVER_LOG10 * log(spectrogram[i]);
  152. tmp[i] = db - EprAtFrequency(params, f, fs, res, nres);
  153. }
  154. return count;
  155. }
  156. double EprAtFrequency(EprSourceParams *params, double f, int fs,
  157. EprResonance *res, int n_res) {
  158. double source = 0;
  159. if (params)
  160. source = params->gaindb +
  161. params->slopedepthdb * (pow(M_E, params->slope * f) - 1);
  162. double accu = 0.0000001; // TODO: use minimal value here
  163. for (int i = 0; i < n_res; i++) {
  164. double x = EprResonanceAtFrequency(&res[i], f, fs);
  165. assert(!isnan(x));
  166. if (res[i].enabled) accu += x;
  167. }
  168. return (TWENTY_OVER_LOG10 * log(accu)) + source;
  169. }
  170. double EprResonanceAtFrequency(EprResonance *me, double f, int fs) {
  171. if (me->a == 0) return 0.0;
  172. // klatt filter second order
  173. double w = 2 * M_PI * f / (double)fs;
  174. double real = 1 - me->b * cos(w) - me->c * cos(2 * w);
  175. double imag = 0 - me->b * sin(w) - me->c * sin(2 * w);
  176. return me->a / sqrt(real * real + imag * imag) / me->norm;
  177. // we only need to know the absolute value of our complex number
  178. }
  179. void EprResonanceUpdate(EprResonance *me, int fs) {
  180. if (me->gain_db == 0) {
  181. me->a = 0;
  182. me->b = 0;
  183. me->c = 0;
  184. return;
  185. }
  186. double tmp = exp(-M_PI * me->bw / (double)fs);
  187. me->c = -tmp * tmp;
  188. me->b = 2.0 * tmp * cos(2 * M_PI * me->f / (double)fs);
  189. me->a = 1.0 - me->b - me->c;
  190. me->norm = 1;
  191. me->norm = EprResonanceAtFrequency(me, me->f, fs);
  192. me->a *= exp(me->gain_db / TWENTY_OVER_LOG10);
  193. }