make_g168_css.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. * SpanDSP - a series of DSP components for telephony
  3. *
  4. * makecss.c - Create the composite source signal (CSS) for G.168 testing.
  5. *
  6. * Written by Steve Underwood <steveu@coppice.org>
  7. *
  8. * Copyright (C) 2003 Steve Underwood
  9. *
  10. * All rights reserved.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2, as
  14. * published by the Free Software Foundation.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24. */
  25. /*! \page makecss_page CSS construction for G.168 testing
  26. \section makecss_page_sec_1 What does it do?
  27. ???.
  28. \section makecss_page_sec_2 How does it work?
  29. ???.
  30. */
  31. #if defined(HAVE_CONFIG_H)
  32. #include "config.h"
  33. #endif
  34. #include <stdlib.h>
  35. #include <unistd.h>
  36. #include <string.h>
  37. #include <time.h>
  38. #include <stdio.h>
  39. #include <fcntl.h>
  40. #include <sndfile.h>
  41. #if defined(HAVE_FFTW3_H)
  42. #include <fftw3.h>
  43. #else
  44. #include <fftw.h>
  45. #endif
  46. #include "spandsp.h"
  47. #include "spandsp/g168models.h"
  48. #if !defined(NULL)
  49. #define NULL (void *) 0
  50. #endif
  51. #define FAST_SAMPLE_RATE 44100.0
  52. #define C1_VOICED_SAMPLES 2144 /* 48.62ms at 44100 samples/second => 2144.142 */
  53. #define C1_NOISE_SAMPLES 8820 /* 200ms at 44100 samples/second => 8820.0 */
  54. #define C1_SILENCE_SAMPLES 4471 /* 101.38ms at 44100 samples/second => 4470.858 */
  55. #define C3_VOICED_SAMPLES 3206 /* 72.69ms at 44100 samples/second => 3205.629 */
  56. #define C3_NOISE_SAMPLES 8820 /* 200ms at 44100 samples/second => 8820.0 */
  57. #define C3_SILENCE_SAMPLES 5614 /* 127.31ms at 44100 samples/second => 5614.371 */
  58. static double scaling(double f, double start, double end, double start_gain, double end_gain)
  59. {
  60. double scale;
  61. scale = start_gain + (f - start)*(end_gain - start_gain)/(end - start);
  62. return scale;
  63. }
  64. /*- End of function --------------------------------------------------------*/
  65. static double peak(const int16_t amp[], int len)
  66. {
  67. int16_t peak;
  68. int i;
  69. peak = 0;
  70. for (i = 0; i < len; i++)
  71. {
  72. if (abs(amp[i]) > peak)
  73. peak = abs(amp[i]);
  74. }
  75. return peak/32767.0;
  76. }
  77. /*- End of function --------------------------------------------------------*/
  78. static double rms(const int16_t amp[], int len)
  79. {
  80. double ms;
  81. int i;
  82. ms = 0.0;
  83. for (i = 0; i < len; i++)
  84. ms += amp[i]*amp[i];
  85. return sqrt(ms/len)/32767.0;
  86. }
  87. /*- End of function --------------------------------------------------------*/
  88. static double rms_to_dbm0(double rms)
  89. {
  90. return 20.0*log10(rms) + DBM0_MAX_POWER;
  91. }
  92. /*- End of function --------------------------------------------------------*/
  93. static double rms_to_db(double rms)
  94. {
  95. return 20.0*log10(rms);
  96. }
  97. /*- End of function --------------------------------------------------------*/
  98. int main(int argc, char *argv[])
  99. {
  100. #if defined(HAVE_FFTW3_H)
  101. double in[8192][2];
  102. double out[8192][2];
  103. #else
  104. fftw_complex in[8192];
  105. fftw_complex out[8192];
  106. #endif
  107. fftw_plan p;
  108. int16_t voiced_sound[8192];
  109. int16_t noise_sound[8830];
  110. int16_t silence_sound[8192];
  111. int i;
  112. int voiced_length;
  113. int randy;
  114. double f;
  115. double pk;
  116. double ms;
  117. double scale;
  118. SNDFILE *filehandle;
  119. SF_INFO info;
  120. awgn_state_t *noise_source;
  121. memset(&info, 0, sizeof(info));
  122. info.frames = 0;
  123. info.samplerate = FAST_SAMPLE_RATE;
  124. info.channels = 1;
  125. info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
  126. info.sections = 1;
  127. info.seekable = 1;
  128. if ((filehandle = sf_open("sound_c1.wav", SFM_WRITE, &info)) == NULL)
  129. {
  130. fprintf(stderr, " Failed to open result file\n");
  131. exit(2);
  132. }
  133. printf("Generate C1\n");
  134. /* The sequence is
  135. 48.62ms of voiced sound from table C.1 of G.168
  136. 200.0ms of pseudo-noise
  137. 101.38ms of silence
  138. The above is then repeated phase inverted.
  139. The voice comes straight from C.1, repeated enough times to
  140. fill out the 48.62ms period - i.e. 16 copies of the sequence.
  141. The pseudo noise section is random numbers filtered by the spectral
  142. pattern in Figure C.2 */
  143. /* The set of C1 voice samples is ready for use in the output file. */
  144. voiced_length = sizeof(css_c1)/sizeof(css_c1[0]);
  145. for (i = 0; i < voiced_length; i++)
  146. voiced_sound[i] = css_c1[i];
  147. pk = peak(voiced_sound, voiced_length);
  148. ms = rms(voiced_sound, voiced_length);
  149. printf("Voiced level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms));
  150. #if defined(HAVE_FFTW3_H)
  151. p = fftw_plan_dft_1d(8192, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
  152. #else
  153. p = fftw_create_plan(8192, FFTW_BACKWARD, FFTW_ESTIMATE);
  154. #endif
  155. for (i = 0; i < 8192; i++)
  156. {
  157. #if defined(HAVE_FFTW3_H)
  158. in[i][0] = 0.0;
  159. in[i][1] = 0.0;
  160. #else
  161. in[i].re = 0.0;
  162. in[i].im = 0.0;
  163. #endif
  164. }
  165. for (i = 1; i <= 3715; i++)
  166. {
  167. f = FAST_SAMPLE_RATE*i/8192.0;
  168. #if 1
  169. if (f < 50.0)
  170. scale = -60.0;
  171. else if (f < 100.0)
  172. scale = scaling(f, 50.0, 100.0, -25.8, -12.8);
  173. else if (f < 200.0)
  174. scale = scaling(f, 100.0, 200.0, -12.8, 17.4);
  175. else if (f < 215.0)
  176. scale = scaling(f, 200.0, 215.0, 17.4, 17.8);
  177. else if (f < 500.0)
  178. scale = scaling(f, 215.0, 500.0, 17.8, 12.2);
  179. else if (f < 1000.0)
  180. scale = scaling(f, 500.0, 1000.0, 12.2, 7.2);
  181. else if (f < 2850.0)
  182. scale = scaling(f, 1000.0, 2850.0, 7.2, 0.0);
  183. else if (f < 3600.0)
  184. scale = scaling(f, 2850.0, 3600.0, 0.0, -2.0);
  185. else if (f < 3660.0)
  186. scale = scaling(f, 3600.0, 3660.0, -2.0, -20.0);
  187. else if (f < 3680.0)
  188. scale = scaling(f, 3600.0, 3680.0, -20.0, -30.0);
  189. else
  190. scale = -60.0;
  191. #else
  192. scale = 0.0;
  193. #endif
  194. randy = ((rand() >> 10) & 0x1) ? 1.0 : -1.0;
  195. #if defined(HAVE_FFTW3_H)
  196. in[i][0] = randy*pow(10.0, scale/20.0)*35.0;
  197. in[8192 - i][0] = -in[i][0];
  198. #else
  199. in[i].re = randy*pow(10.0, scale/20.0)*35.0;
  200. in[8192 - i].re = -in[i].re;
  201. #endif
  202. }
  203. #if defined(HAVE_FFTW3_H)
  204. fftw_execute(p);
  205. #else
  206. fftw_one(p, in, out);
  207. #endif
  208. for (i = 0; i < 8192; i++)
  209. {
  210. #if defined(HAVE_FFTW3_H)
  211. noise_sound[i] = out[i][1];
  212. #else
  213. noise_sound[i] = out[i].im;
  214. #endif
  215. }
  216. pk = peak(noise_sound, 8192);
  217. ms = rms(noise_sound, 8192);
  218. printf("Filtered noise level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms));
  219. for (i = 0; i < 8192; i++)
  220. silence_sound[i] = 0.0;
  221. for (i = 0; i < 16; i++)
  222. sf_writef_short(filehandle, voiced_sound, voiced_length);
  223. printf("%d samples of voice\n", 16*voiced_length);
  224. sf_writef_short(filehandle, noise_sound, 8192);
  225. sf_writef_short(filehandle, noise_sound, C1_NOISE_SAMPLES - 8192);
  226. printf("%d samples of noise\n", C1_NOISE_SAMPLES);
  227. sf_writef_short(filehandle, silence_sound, C1_SILENCE_SAMPLES);
  228. printf("%d samples of silence\n", C1_SILENCE_SAMPLES);
  229. /* Now phase invert the C1 set of samples. */
  230. voiced_length = sizeof(css_c1)/sizeof(css_c1[0]);
  231. for (i = 0; i < voiced_length; i++)
  232. voiced_sound[i] = -css_c1[i];
  233. for (i = 0; i < 8192; i++)
  234. noise_sound[i] = -noise_sound[i];
  235. for (i = 0; i < 16; i++)
  236. sf_writef_short(filehandle, voiced_sound, voiced_length);
  237. printf("%d samples of voice\n", 16*voiced_length);
  238. sf_writef_short(filehandle, noise_sound, 8192);
  239. sf_writef_short(filehandle, noise_sound, C1_NOISE_SAMPLES - 8192);
  240. printf("%d samples of noise\n", C1_NOISE_SAMPLES);
  241. sf_writef_short(filehandle, silence_sound, C1_SILENCE_SAMPLES);
  242. printf("%d samples of silence\n", C1_SILENCE_SAMPLES);
  243. if (sf_close(filehandle))
  244. {
  245. fprintf(stderr, " Cannot close speech file '%s'\n", "sound_c1.wav");
  246. exit(2);
  247. }
  248. memset(&info, 0, sizeof(info));
  249. info.frames = 0;
  250. info.samplerate = FAST_SAMPLE_RATE;
  251. info.channels = 1;
  252. info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
  253. info.sections = 1;
  254. info.seekable = 1;
  255. if ((filehandle = sf_open("sound_c3.wav", SFM_WRITE, &info)) == NULL)
  256. {
  257. fprintf(stderr, " Failed to open result file\n");
  258. exit(2);
  259. }
  260. printf("Generate C3\n");
  261. /* The sequence is
  262. 72.69ms of voiced sound from table C.3 of G.168
  263. 200.0ms of pseudo-noise
  264. 127.31ms of silence
  265. The above is then repeated phase inverted.
  266. The voice comes straight from C.3, repeated enough times to
  267. fill out the 72.69ms period - i.e. 14 copies of the sequence.
  268. The pseudo noise section is AWGN filtered by the spectral
  269. pattern in Figure C.2. Since AWGN has the quality of being its
  270. own Fourier transform, we can use an approach like the one above
  271. for the C1 signal, using AWGN samples instead of randomly alternating
  272. ones and zeros. */
  273. /* Take the supplied set of C3 voice samples. */
  274. voiced_length = (sizeof(css_c3)/sizeof(css_c3[0]));
  275. for (i = 0; i < voiced_length; i++)
  276. voiced_sound[i] = css_c3[i];
  277. pk = peak(voiced_sound, voiced_length);
  278. ms = rms(voiced_sound, voiced_length);
  279. printf("Voiced level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms));
  280. noise_source = awgn_init_dbm0(NULL, 7162534, rms_to_dbm0(ms));
  281. for (i = 0; i < 8192; i++)
  282. noise_sound[i] = awgn(noise_source);
  283. pk = peak(noise_sound, 8192);
  284. ms = rms(noise_sound, 8192);
  285. printf("Unfiltered noise level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms));
  286. /* Now filter them */
  287. #if defined(HAVE_FFTW3_H)
  288. p = fftw_plan_dft_1d(8192, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
  289. #else
  290. p = fftw_create_plan(8192, FFTW_BACKWARD, FFTW_ESTIMATE);
  291. #endif
  292. for (i = 0; i < 8192; i++)
  293. {
  294. #if defined(HAVE_FFTW3_H)
  295. in[i][0] = 0.0;
  296. in[i][1] = 0.0;
  297. #else
  298. in[i].re = 0.0;
  299. in[i].im = 0.0;
  300. #endif
  301. }
  302. for (i = 1; i <= 3715; i++)
  303. {
  304. f = FAST_SAMPLE_RATE*i/8192.0;
  305. #if 1
  306. if (f < 50.0)
  307. scale = -60.0;
  308. else if (f < 100.0)
  309. scale = scaling(f, 50.0, 100.0, -25.8, -12.8);
  310. else if (f < 200.0)
  311. scale = scaling(f, 100.0, 200.0, -12.8, 17.4);
  312. else if (f < 215.0)
  313. scale = scaling(f, 200.0, 215.0, 17.4, 17.8);
  314. else if (f < 500.0)
  315. scale = scaling(f, 215.0, 500.0, 17.8, 12.2);
  316. else if (f < 1000.0)
  317. scale = scaling(f, 500.0, 1000.0, 12.2, 7.2);
  318. else if (f < 2850.0)
  319. scale = scaling(f, 1000.0, 2850.0, 7.2, 0.0);
  320. else if (f < 3600.0)
  321. scale = scaling(f, 2850.0, 3600.0, 0.0, -2.0);
  322. else if (f < 3660.0)
  323. scale = scaling(f, 3600.0, 3660.0, -2.0, -20.0);
  324. else if (f < 3680.0)
  325. scale = scaling(f, 3600.0, 3680.0, -20.0, -30.0);
  326. else
  327. scale = -60.0;
  328. #else
  329. scale = 0.0;
  330. #endif
  331. #if defined(HAVE_FFTW3_H)
  332. in[i][0] = noise_sound[i]*pow(10.0, scale/20.0)*0.0106;
  333. in[8192 - i][0] = -in[i][0];
  334. #else
  335. in[i].re = noise_sound[i]*pow(10.0, scale/20.0)*0.0106;
  336. in[8192 - i].re = -in[i].re;
  337. #endif
  338. }
  339. #if defined(HAVE_FFTW3_H)
  340. fftw_execute(p);
  341. #else
  342. fftw_one(p, in, out);
  343. #endif
  344. for (i = 0; i < 8192; i++)
  345. {
  346. #if defined(HAVE_FFTW3_H)
  347. noise_sound[i] = out[i][1];
  348. #else
  349. noise_sound[i] = out[i].im;
  350. #endif
  351. }
  352. pk = peak(noise_sound, 8192);
  353. ms = rms(noise_sound, 8192);
  354. printf("Filtered noise level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms));
  355. for (i = 0; i < 14; i++)
  356. sf_writef_short(filehandle, voiced_sound, voiced_length);
  357. printf("%d samples of voice\n", 14*voiced_length);
  358. sf_writef_short(filehandle, noise_sound, 8192);
  359. sf_writef_short(filehandle, noise_sound, C3_NOISE_SAMPLES - 8192);
  360. printf("%d samples of noise\n", C3_NOISE_SAMPLES);
  361. sf_writef_short(filehandle, silence_sound, C3_SILENCE_SAMPLES);
  362. printf("%d samples of silence\n", C3_SILENCE_SAMPLES);
  363. /* Now phase invert the C3 set of samples. */
  364. voiced_length = (sizeof(css_c3)/sizeof(css_c3[0]));
  365. for (i = 0; i < voiced_length; i++)
  366. voiced_sound[i] = -css_c3[i];
  367. for (i = 0; i < 8192; i++)
  368. noise_sound[i] = -noise_sound[i];
  369. for (i = 0; i < 14; i++)
  370. sf_writef_short(filehandle, voiced_sound, voiced_length);
  371. printf("%d samples of voice\n", 14*voiced_length);
  372. sf_writef_short(filehandle, noise_sound, 8192);
  373. sf_writef_short(filehandle, noise_sound, C3_NOISE_SAMPLES - 8192);
  374. printf("%d samples of noise\n", C3_NOISE_SAMPLES);
  375. sf_writef_short(filehandle, silence_sound, C3_SILENCE_SAMPLES);
  376. printf("%d samples of silence\n", C3_SILENCE_SAMPLES);
  377. if (sf_close(filehandle))
  378. {
  379. fprintf(stderr, " Cannot close speech file '%s'\n", "sound_c3.wav");
  380. exit(2);
  381. }
  382. fftw_destroy_plan(p);
  383. return 0;
  384. }
  385. /*- End of function --------------------------------------------------------*/
  386. /*- End of file ------------------------------------------------------------*/