MFCC.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* MFCC.cpp
  2. *
  3. * Mel Frequency Cepstral Coefficients class.
  4. *
  5. * Copyright (C) 1993-2017 David Weenink
  6. *
  7. * This code is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * This code is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /*
  21. * djmw 20020813 GPL header
  22. * djmw 20110304 Thing_new
  23. */
  24. #include "MFCC.h"
  25. #include "Spectrogram_extensions.h"
  26. #include "NUM2.h"
  27. Thing_implement (MFCC, CC, 1);
  28. void structMFCC :: v_info () {
  29. structCC :: v_info ();
  30. MelderInfo_writeLine (U"Minimum frequency: ", fmin, U" mel");
  31. MelderInfo_writeLine (U"Maximum frequency: ", fmax, U" mel");
  32. }
  33. autoMFCC MFCC_create (double tmin, double tmax, integer nt, double dt, double t1, integer maximumNumberOfCoefficients, double fmin_mel, double fmax_mel) {
  34. try {
  35. autoMFCC me = Thing_new (MFCC);
  36. CC_init (me.get(), tmin, tmax, nt, dt, t1, maximumNumberOfCoefficients, fmin_mel, fmax_mel);
  37. return me;
  38. } catch (MelderError) {
  39. Melder_throw (U"MFCC not created.");
  40. }
  41. }
  42. void MFCC_lifter (MFCC me, integer lifter) {
  43. try {
  44. Melder_assert (lifter > 0);
  45. autoNUMvector<double> c (1, my maximumNumberOfCoefficients);
  46. for (integer i = 1; i <= my maximumNumberOfCoefficients; i ++)
  47. c [i] = (1 + lifter / 2 * sin (NUMpi * i / lifter));
  48. for (integer frame = 1; frame <= my nx; frame ++) {
  49. CC_Frame cf = & my frame [frame];
  50. for (integer i = 1; i <= cf -> numberOfCoefficients; i ++)
  51. cf -> c [i] *= c [i];
  52. }
  53. } catch (MelderError) {
  54. Melder_throw (me, U": not lifted.");
  55. }
  56. }
  57. autoTableOfReal MFCC_to_TableOfReal (MFCC me, bool includeC0) {
  58. try {
  59. integer numberOfColumns = my maximumNumberOfCoefficients + (includeC0 ? 1 : 0);
  60. autoTableOfReal thee = TableOfReal_create (my nx, numberOfColumns);
  61. for (integer i = 1; i <= numberOfColumns; i ++)
  62. TableOfReal_setColumnLabel (thee.get(), i, Melder_cat (U"c", includeC0 ? i - 1 : i));
  63. integer offset = includeC0 ? 1 : 0;
  64. for (integer iframe = 1; iframe <= my nx; iframe ++) {
  65. CC_Frame cf = & my frame [iframe];
  66. for (integer j = 1; j <= cf -> numberOfCoefficients; j ++)
  67. thy data [iframe] [j + offset] = cf -> c [j];
  68. if (includeC0)
  69. thy data [iframe] [1] = cf -> c0;
  70. }
  71. return thee;
  72. } catch (MelderError) {
  73. Melder_throw (me, U": not converted to TabelOfReal.");
  74. }
  75. }
  76. // as_Sound not to_Sound
  77. autoSound MFCC_to_Sound (MFCC me) {
  78. try {
  79. autoSound thee = Sound_create (my maximumNumberOfCoefficients, my xmin, my xmax, my nx, my dx, my x1);
  80. for (integer iframe = 1; iframe <= my nx; iframe ++) {
  81. CC_Frame cf = & my frame [iframe];
  82. for (integer j = 1; j <= my maximumNumberOfCoefficients; j ++)
  83. thy z [j] [iframe] = cf -> c [j];
  84. }
  85. return thee;
  86. } catch (MelderError) {
  87. Melder_throw (me, U": not represented as Sound.");
  88. }
  89. }
  90. autoSound MFCCs_crossCorrelate (MFCC me, MFCC thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) {
  91. try {
  92. if (my dx != thy dx)
  93. Melder_throw (U"The samplings of the two MFCC's have to be equal.");
  94. if (my maximumNumberOfCoefficients != thy maximumNumberOfCoefficients)
  95. Melder_throw (U"The number of coefficients in the two MFCC's have to be equal.");
  96. autoSound target = MFCC_to_Sound (me);
  97. autoSound source = MFCC_to_Sound (thee);
  98. autoSound cc = Sounds_crossCorrelate (target.get(), source.get(), scaling, signalOutsideTimeDomain);
  99. return cc;
  100. } catch (MelderError) {
  101. Melder_throw (U"No cross-correlation between ", me, U" and ", thee, U" calculated.");
  102. }
  103. }
  104. autoSound MFCCs_convolve (MFCC me, MFCC thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) {
  105. try {
  106. Melder_require (my dx == thy dx,
  107. U"The samplings of the two MFCC's should be equal.");
  108. Melder_require (my maximumNumberOfCoefficients == thy maximumNumberOfCoefficients,
  109. U"The number of coefficients in the two MFCC's should be equal.");
  110. autoSound target = MFCC_to_Sound (me);
  111. autoSound source = MFCC_to_Sound (thee);
  112. autoSound cc = Sounds_convolve (target.get(), source.get(), scaling, signalOutsideTimeDomain);
  113. return cc;
  114. } catch (MelderError) {
  115. Melder_throw (me, U" and ", thee, U" not convolved.");
  116. }
  117. }
  118. static double CC_Frames_distance (CC_Frame me, CC_Frame thee, bool includeEnergy) {
  119. double dist = 0;
  120. if (includeEnergy) {
  121. double d0 = my c0 - thy c0;
  122. dist += d0 * d0;
  123. }
  124. for (integer i = 1; i <= my numberOfCoefficients; i ++) {
  125. double di = my c [i] - thy c [i];
  126. dist += di * di;
  127. }
  128. return sqrt (dist);
  129. }
  130. /* 1: cepstral difference function (d)
  131. * 2: spectral stability (dstab)
  132. * 3: spectral center of gravity (gs)
  133. * 4: stable internal duration
  134. */
  135. autoMatrix MFCC_to_Matrix_features (MFCC me, double windowLength, bool includeEnergy) {
  136. try {
  137. integer nw = Melder_ifloor (windowLength / my dx / 2.0);
  138. autoMelSpectrogram him = MFCC_to_MelSpectrogram (me, 0, 0, 1);
  139. autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1.0, 4.0, 4, 1.0, 1.0);
  140. thy z [1] [1] = thy z [1] [my nx] = 0; // first & last frame
  141. for (integer iframe = 2; iframe <= my nx - 1; iframe ++) {
  142. CC_Frame cfi = & my frame [iframe];
  143. // 1. cepstral difference
  144. integer nwi = ( iframe > nw ? nw : iframe - 1 );
  145. if (nwi > my nx - iframe)
  146. nwi = my nx - iframe;
  147. double numer = 0.0;
  148. for (integer j = 1; j <= nwi; j ++)
  149. numer += (double) j * (double) j;
  150. numer *= 2.0;
  151. double dsq = 0.0;
  152. if (includeEnergy) {
  153. longdouble sumj = 0.0;
  154. for (integer j = 1; j <= nwi; j ++) {
  155. CC_Frame cfp = & my frame [iframe + j];
  156. CC_Frame cfm = & my frame [iframe - j];
  157. sumj += j * (cfp -> c0 - cfm -> c0);
  158. }
  159. sumj /= numer;
  160. dsq += sumj * sumj;
  161. }
  162. for (integer i = 1; i <= my maximumNumberOfCoefficients; i ++) {
  163. longdouble sumj = 0.0;
  164. for (integer j = 1; j <= nwi; j ++) {
  165. CC_Frame cfp = & my frame [iframe + j];
  166. CC_Frame cfm = & my frame [iframe - j];
  167. sumj += j * (cfp -> c [j] - cfm -> c [j]);
  168. }
  169. sumj /= numer;
  170. dsq += sumj * sumj;
  171. }
  172. thy z [1] [iframe] = dsq;
  173. // 2: spectral stability (dstab)
  174. CC_Frame cfp = & my frame [iframe + 1];
  175. CC_Frame cfm = & my frame [iframe - 1];
  176. double dim1 = CC_Frames_distance (cfi, cfm, includeEnergy);
  177. double dip1 = CC_Frames_distance (cfi, cfp, includeEnergy);
  178. thy z [2] [iframe] = (dim1 + dip1) / 2.0;
  179. // 3: spectral centere of gravity (gs)
  180. longdouble msm = 0.0, sm = 0.0;
  181. for (integer j = 1; j <= his ny; j ++) {
  182. sm += his z [j] [iframe];
  183. msm += j * his z [j] [iframe];
  184. }
  185. double gs = ( sm == 0.0 ? 0.0 : (double) (msm / sm) );
  186. thy z [3] [iframe] = gs;
  187. // 4: stable internal duration
  188. }
  189. return thee;
  190. } catch (MelderError) {
  191. Melder_throw (me, U": no features calculated.");
  192. }
  193. }
  194. /* End of file MFCC.cpp */