Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

578 lines
14 KiB

  1. /******************************************************************************
  2. * bispectrum.cpp *
  3. *----------------*
  4. * I/O library functions for extended speech files (vapi format)
  5. *------------------------------------------------------------------------------
  6. * Copyright (C) 1999 Entropic, Inc
  7. * Copyright (C) 2000 Microsoft Corporation Date: 03/02/00
  8. * All Rights Reserved
  9. *
  10. ********************************************************************* PACOG ***/
  11. #include "sigprocInt.h"
  12. enum {WINDOW_OPTIMUM, WINDOW_PARZEN};
  13. #define UNACCESS 1.0e08 // a big value used in unaccess initialization
  14. class Double2D
  15. {
  16. public:
  17. Double2D (int dim) {
  18. m_iSize = dim;
  19. m_ppdData = new double*[m_iSize];
  20. m_ppdData[0] = new double[m_iSize * m_iSize];
  21. for (int i = 1; i< m_iSize; i++)
  22. {
  23. m_ppdData[i] = m_ppdData[0]+ i * m_iSize;
  24. }
  25. }
  26. ~Double2D() {
  27. delete[] m_ppdData[0];
  28. delete[] m_ppdData;
  29. }
  30. Double2D& operator=(Double2D& orig)
  31. {
  32. if (m_ppdData) {
  33. delete[] m_ppdData[0];
  34. delete[] m_ppdData;
  35. }
  36. m_iSize = orig.m_iSize;
  37. m_ppdData = new double* [m_iSize];
  38. m_ppdData[0] = new double[m_iSize * m_iSize];
  39. memcpy(m_ppdData, orig.m_ppdData, sizeof(double)* m_iSize * m_iSize);
  40. for (int i = 1; i< m_iSize; i++)
  41. {
  42. m_ppdData[i] = m_ppdData[0]+ i * m_iSize;
  43. }
  44. return (*this);
  45. }
  46. double& Element(int a, int b)
  47. {
  48. return m_ppdData[a][b];
  49. };
  50. int Size(){
  51. return m_iSize;
  52. }
  53. private:
  54. double** m_ppdData;
  55. int m_iSize;
  56. };
  57. static struct _complex**
  58. GetBispectrumSeg(double *data, int nData, int nSeg, int L, int winType, double *workReal, double *workImag);
  59. static struct _complex** Alloc2DimComplex(int dim);
  60. static Double2D Get3rdMomentSeqLong (double *data, int N, int M, int L);
  61. static double Get3rdMomentSeq (int i, int j, int inDataLen, double *data);
  62. static Double2D Get2DimWin (int len, int winType);
  63. static double* GetParzenWin (int length);
  64. static double* GetOptimumWin (int length);
  65. /*
  66. *-----------------------------------------------------------------------------
  67. *
  68. * Optimum window (minimum bispectrm bias supremum) used for
  69. * bispectrum estimation (indirect method)
  70. * Note : the window length is 2 * len + 1, but output [0, 2 *length]
  71. * because of [-len, len]
  72. *
  73. *-----------------------------------------------------------------------------
  74. */
  75. double* GetOptimumWin (int length)
  76. {
  77. double* x;
  78. int i;
  79. x = new double[2 * length + 1];
  80. if (x)
  81. {
  82. for (i=-length; i<=length; i++)
  83. {
  84. x[i + length] = 1.0 / M_PI * fabs(sin(M_PI * (double)i / (double)length))
  85. + (1.0 - fabs((double)i)/length)*(cos(M_PI * (double)i / (double)length));
  86. }
  87. }
  88. return x;
  89. }
  90. /*
  91. *-----------------------------------------------------------------------------
  92. *
  93. * Parzen window used for bispectrum estimation (indirect method)
  94. * Note : the window length is 2 * len + 1, the output size is [0, 2 *length]
  95. * from [-len, len]
  96. *
  97. *-----------------------------------------------------------------------------
  98. */
  99. double* GetParzenWin (int length)
  100. {
  101. double* x;
  102. double d;
  103. int i;
  104. x = new double [2 * length + 1];
  105. if (x)
  106. {
  107. for (i=-length; i<=length; i++)
  108. {
  109. if (abs(i) <= length/2)
  110. {
  111. d = fabs((double)i/(double)length);
  112. x[i + length] = 1.0 - 6.0 * d * d + 6.0 * d * d * d;
  113. }
  114. else
  115. {
  116. x[i + length] = 2.0 * (1.0 - fabs((double)i * i * i) / length);
  117. }
  118. }
  119. }
  120. return x;
  121. }
  122. /*
  123. *-----------------------------------------------------------------------------
  124. *
  125. * Get a 2-dim window used for
  126. * bispectrum estimation (indirect method)
  127. * Note : the output matrix is [2 * len + 1] x [2 * len + 1]
  128. * corresponding to [-len, len] x [-len, len]
  129. *
  130. *-----------------------------------------------------------------------------
  131. */
  132. Double2D Get2DimWin (int len, int winType)
  133. {
  134. double* winData = NULL;
  135. int i;
  136. int j;
  137. int newLen;
  138. assert(len > 0);
  139. newLen = 2*len + 1;
  140. Double2D x(newLen);
  141. switch(winType)
  142. {
  143. case WINDOW_OPTIMUM:
  144. winData = GetOptimumWin(len);
  145. break;
  146. case WINDOW_PARZEN:
  147. winData = GetParzenWin(len);
  148. break;
  149. default:
  150. break;
  151. }
  152. if (winData)
  153. {
  154. for (i=0; i<newLen; i++)
  155. {
  156. for (j=0; j<newLen; j++)
  157. {
  158. if(i >= j)
  159. {
  160. x.Element(i,j) = winData[i] * winData[j] * winData[i - j];
  161. }
  162. else
  163. {
  164. x.Element(i,j) = winData[i] * winData[j] * winData[j - i];
  165. }
  166. }
  167. }
  168. }
  169. delete[] winData;
  170. return x;
  171. }
  172. /*
  173. *-----------------------------------------------------------------------------
  174. *
  175. * Get a 3rd moment sequence for a single segment
  176. *
  177. *-----------------------------------------------------------------------------
  178. */
  179. static double
  180. Get3rdMomentSeq (int i, int j, int inDataLen, double *data)
  181. {
  182. double d;
  183. int m;
  184. int s1;
  185. int s2;
  186. s1 = __max(0, -i);
  187. s1 = __max(s1, -j);
  188. s2 = __min(inDataLen-1, inDataLen-1-i);
  189. s2 = __min(s2, inDataLen-1-j);
  190. d = (double)0.0;
  191. for(m = s1; m <= s2; m++) {
  192. d += data[m] * data[m+i] * data[m+j];
  193. }
  194. d /= (double)inDataLen;
  195. return d;
  196. }
  197. /*
  198. *-----------------------------------------------------------------------------
  199. *
  200. * Get a 3rd moment sequence for a long segment
  201. * Note : - the output matrix is [2 * len + 1] x [2 * len + 1]
  202. * corresponding to [-len, len] x [-len, len]
  203. * - N is divided into N = K * M; each segemnt has M records
  204. * - L < M - 1;
  205. *
  206. *-----------------------------------------------------------------------------
  207. */
  208. Double2D Get3rdMomentSeqLong (double *data, int N, int M, int L)
  209. {
  210. int K;
  211. int i;
  212. int m;
  213. int n;
  214. assert(N > 0);
  215. assert(M > 0);
  216. assert(data);
  217. RemoveDc (data, N);
  218. if (N % M != 0 || L > M-2)
  219. {
  220. fprintf(stderr, "%s\n", "Error in data segmentation.");
  221. return 0;
  222. }
  223. K = N / M;
  224. Double2D x(2*L + 1);
  225. for (m = -L; m <=L; m++)
  226. {
  227. for (n = -L; n <=L; n++)
  228. {
  229. x.Element(m+L, n+L) = UNACCESS;
  230. }
  231. }
  232. for (m = -L; m <=L; m++)
  233. {
  234. for (n = -L; n <=L; n++)
  235. {
  236. /*
  237. * judge if I could use symmetric properties
  238. */
  239. if (x.Element(n+L, m+L) != UNACCESS)
  240. {
  241. x.Element(m+L, n+L) = x.Element(n+L, m+L);
  242. continue;
  243. }
  244. if (m-n>=-L && m-n <=L && x.Element(-n+L, m-n+L) != UNACCESS)
  245. {
  246. x.Element(m+L, n+L) = x.Element(-n+L, m-n+L);
  247. continue;
  248. }
  249. if (n-m>=-L && n-m <=L && x.Element(n-m+L, -m+L) != UNACCESS)
  250. {
  251. x.Element(m+L, n+L) = x.Element(n-m+L, -m+L);
  252. continue;
  253. }
  254. if (m-n>=-L && m-n <=L && x.Element(m-n+L, -n+L) != UNACCESS)
  255. {
  256. x.Element(m+L, n+L) = x.Element(m-n+L, -n+L);
  257. continue;
  258. }
  259. if (n-m>=-L && n-m <=L && x.Element(m+L, n-m+L) != UNACCESS)
  260. {
  261. x.Element(m+L, n+L) = x.Element(m+L, n-m+L);
  262. continue;
  263. }
  264. /*
  265. * otherwise compute the value
  266. */
  267. x.Element(m+L, n+L) = 0.0;
  268. for (i = 0; i < K; i++)
  269. {
  270. x.Element(m+L, n+L) += Get3rdMomentSeq (m, n, M, &data[i*M]);
  271. }
  272. x.Element(m+L, n+L) /= (double)K;
  273. }
  274. }
  275. return x;
  276. }
  277. /*
  278. *-----------------------------------------------------------------------------
  279. *
  280. * alloc memory for 2-D _complex
  281. *
  282. *-----------------------------------------------------------------------------
  283. */
  284. static struct _complex**
  285. Alloc2DimComplex(int dim)
  286. {
  287. struct _complex **r = NULL;
  288. int i;
  289. r = (struct _complex **)malloc(sizeof(struct _complex*) * dim);
  290. if(!r) {
  291. fprintf(stderr, "%s\n", "Error in memory allocation.");
  292. return NULL;
  293. }
  294. r[0] = (struct _complex*) malloc (sizeof(struct _complex) * dim * dim);
  295. if(!r[0]) {
  296. fprintf(stderr, "%s\n", "Error in memory allocation.");
  297. return NULL;
  298. }
  299. for (i = 1; i < dim; i++) {
  300. r[i] = r[0] + i*dim;
  301. }
  302. return(r);
  303. }
  304. /*
  305. *-----------------------------------------------------------------------------
  306. *
  307. * Get bispectrum estimation for one segment
  308. * Note : - the output matrix is [2 * len + 1] x [2 * len + 1]
  309. * corresponding to [-len, len] x [-len, len]
  310. * - N is divided into N = K * nSeg; each segemnt has nSeg records
  311. * - L < nSeg - 1, L = nSeg - 2;
  312. * - bispectrum length is 2*L+1
  313. *
  314. *-----------------------------------------------------------------------------
  315. */
  316. struct _complex**
  317. GetBispectrumSeg(double *data, int nData, int nSeg, int L, int winType, double *workReal, double *workImag)
  318. {
  319. struct _complex** x = NULL;
  320. register i;
  321. register j;
  322. int temp;
  323. register m;
  324. register n;
  325. int K;
  326. assert(data);
  327. temp = 2*L*L;
  328. Double2D winData = Get2DimWin (L, winType);
  329. if (nData % nSeg != 0)
  330. {
  331. fprintf(stderr, "%s\n", "Error in data segmentation.");
  332. return x;
  333. }
  334. K = nData / nSeg;
  335. Double2D& r = Get3rdMomentSeqLong (data, nData, nSeg, L);
  336. for (m = -L; m <= L; m++)
  337. {
  338. for(n = -L; n <= L; n++)
  339. {
  340. r.Element(m+L, n+L) *= winData.Element(m+L, n+L);
  341. }
  342. }
  343. x = Alloc2DimComplex(2*L + 1);
  344. for(i = -L; i <= L; i++) {
  345. for(j = -L; j <= L; j++) {
  346. x[i+L][j+L].x = UNACCESS;
  347. }
  348. }
  349. for(i = -L; i <= L; i++) {
  350. for(j = -L; j <= L; j++) {
  351. /*
  352. * judge if I could use symetric properties
  353. */
  354. if(x[j+L][i+L].x != UNACCESS) {
  355. x[i+L][j+L] = x[j+L][i+L];
  356. continue;
  357. }
  358. if(x[-j+L][-i+L].x != UNACCESS) {
  359. x[i+L][j+L] = x[-j+L][-i+L];
  360. continue;
  361. }
  362. if(-i-j>=-L && -i-j <=L && x[-i-j+L][j+L].x != UNACCESS) {
  363. x[i+L][j+L] = x[-i-j+L][j+L];
  364. continue;
  365. }
  366. if(-i-j>=-L && -i-j <=L && x[i+L][-i-j+L].x != UNACCESS) {
  367. x[i+L][j+L] = x[i+L][-i-j+L];
  368. continue;
  369. }
  370. if(-i-j>=-L && -i-j <=L && x[-i-j+L][i+L].x != UNACCESS) {
  371. x[i+L][j+L] = x[-i-j+L][i+L];
  372. continue;
  373. }
  374. if(-i-j>=-L && -i-j <=L && x[j+L][-i-j+L].x != UNACCESS) {
  375. x[i+L][j+L] = x[j+L][-i-j+L];
  376. continue;
  377. }
  378. /*
  379. * otherwise, compute the value
  380. */
  381. x[i+L][j+L].x = 0.0;
  382. x[i+L][j+L].y = 0.0;
  383. for(m = -L; m <= L; m++) {
  384. for(n = -L; n <= L; n++) {
  385. x[i+L][j+L].x += r.Element(m+L, n+L) * workReal[i*m + j*n + temp];
  386. x[i+L][j+L].y += r.Element(m+L, n+L) * workImag[i*m + j*n + temp];
  387. }
  388. }
  389. // printf("\15bispectrum processing ... %.2f%% %.2f%% -> ", (double)(i+L) / (double)(2*L +1) * 100.0,
  390. // (double)(j+L) / (double)(2*L +1) * 100.0);
  391. }
  392. printf("\15bispectrum processing ... %.2f%% ->", (double)(i+L) / (double)(2*L +1) * 100.0);
  393. }
  394. return x;
  395. }
  396. /*
  397. *-----------------------------------------------------------------------------
  398. *
  399. * Get bispectrum estimation for speech data
  400. * Note :
  401. * - nLenMs is length of speech in ms
  402. * - nSpec is the length of bispectrum
  403. * - num is number of output bispectrum
  404. *
  405. *-----------------------------------------------------------------------------
  406. */
  407. struct _complex***
  408. GetBispectrum(double *data, int nLenMs, int frameMs, int segMs,
  409. int specOrder, double sf, int *num, int *nSpec)
  410. {
  411. struct _complex*** x = NULL;
  412. double *extData = NULL;
  413. double *workReal = NULL;
  414. double *workImag = NULL;
  415. double d;
  416. int newDataLen;
  417. int i;
  418. int nData;
  419. int nWin;
  420. int nSeg;
  421. int L;
  422. assert(data);
  423. nData = (int)(nLenMs * sf / 1000.0);
  424. nWin = (int)(frameMs * sf / 1000.0);
  425. nSeg = (int)(segMs * sf / 1000.0);
  426. *num = nData / nWin;
  427. if(nData % nWin != 0) {
  428. *num += 1;
  429. }
  430. newDataLen = nWin * (*num);
  431. L = specOrder;
  432. *nSpec = 2*L + 1;
  433. /*
  434. * Add zero up to reqired length
  435. */
  436. extData = (double *)malloc(sizeof(*extData) * newDataLen);
  437. if(!extData) {
  438. fprintf(stderr, "%s\n", "Error in memory allocation.");
  439. return NULL;
  440. }
  441. for(i=0; i<newDataLen; i++){
  442. if(i < nData) {
  443. extData[i] = data[i];
  444. } else {
  445. extData[i] = 0.0;
  446. }
  447. }
  448. /*
  449. * work variables used for speed up
  450. */
  451. workReal = (double *)malloc(sizeof(*workReal) * (4 * L * L +1));
  452. if(!workReal) {
  453. fprintf(stderr, "%s\n", "Error in memory allocation.");
  454. return NULL;
  455. }
  456. workImag = (double *)malloc(sizeof(*workImag) * (4 * L * L +1));
  457. if(!workImag) {
  458. fprintf(stderr, "%s\n", "Error in memory allocation.");
  459. return NULL;
  460. }
  461. for(i=-2* L * L; i<=2* L * L; i++) {
  462. d = M_PI * ((double)i / (double)L);
  463. workReal[i+2* L * L] = cos(d);
  464. workImag[i+2* L * L] = -sin(d);
  465. }
  466. /*
  467. * get bispectrum
  468. */
  469. x = (struct _complex ***)malloc(sizeof(struct _complex**) * (*num));
  470. if(!x) {
  471. fprintf(stderr, "%s\n", "Error in memory allocation.");
  472. return NULL;
  473. }
  474. for (i=0; i<*num; i++) {
  475. printf("\15bispectrum processing ... %.2f%%", (double)i / (double)(*num) * 100.0);
  476. x[i] = GetBispectrumSeg(&extData[i*nWin], nWin, nSeg, L, WINDOW_OPTIMUM,
  477. workReal, workImag);
  478. }
  479. printf("\15bispectrum processing ... %.2f%%\n", 100.0);
  480. if(extData) {
  481. free(extData);
  482. }
  483. if(workReal) {
  484. free(workReal);
  485. }
  486. if(workImag) {
  487. free(workImag);
  488. }
  489. return x;
  490. }