specpinfo.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
  3. * http://www.trevorwishart.co.uk
  4. * http://www.composersdesktop.com
  5. *
  6. This file is part of the CDP System.
  7. The CDP System is free software; you can redistribute it
  8. and/or modify it under the terms of the GNU Lesser General Public
  9. License as published by the Free Software Foundation; either
  10. version 2.1 of the License, or (at your option) any later version.
  11. The CDP System is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License along with the CDP System; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18. 02111-1307 USA
  19. *
  20. */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <memory.h>
  24. #include <structures.h>
  25. #include <tkglobals.h>
  26. #include <pnames.h>
  27. #include <globcon.h>
  28. #include <processno.h>
  29. #include <modeno.h>
  30. #include <arrays.h>
  31. #include <specpinfo.h>
  32. #include <cdpmain.h>
  33. #include <formants.h>
  34. #include <speccon.h>
  35. #include <sfsys.h>
  36. #include <osbind.h>
  37. #include <float.h>
  38. #include <specpinfo.h>
  39. static int do_specpinfo(dataptr dz);
  40. static int specpzeros(dataptr dz);
  41. static int prescale_transposition_data(dataptr dz);
  42. static int generate_noise_in_buffer(double noischan_amp,dataptr dz);
  43. static int generate_tone_in_buffer(double pre_totalamp,double thisfrq,dataptr dz);
  44. static int preset_chanfrqs_to_chancentres(dataptr dz);
  45. static int construct_screen_message(dataptr dz);
  46. /**************************** SPECPINFO *********************/
  47. int specpinfo(dataptr dz)
  48. {
  49. int exit_status, valid_pitch_data = FALSE;
  50. int n;
  51. if(dz->is_transpos) {
  52. if((dz->transpos = (float *)malloc(dz->wlength * sizeof(float)))==NULL) {
  53. sprintf(errstr,"INSUFFICIENT MEMORY for transposition array.\n");
  54. return(MEMORY_ERROR);
  55. }
  56. for(n=0;n<dz->wlength;n++)
  57. dz->transpos[n] = 1.0f; /* DEFAULT: no transposition */
  58. }
  59. for(n=0;n<dz->wlength;n++) {
  60. if(dz->pitches[n] > FLTERR) {
  61. valid_pitch_data = 1;
  62. break;
  63. }
  64. }
  65. if(!valid_pitch_data) {
  66. sprintf(errstr,"No valid pitches found in input data.\n");
  67. return(DATA_ERROR);
  68. }
  69. switch(dz->process) {
  70. case(P_INFO):
  71. if((exit_status = do_specpinfo(dz))<0)
  72. return(exit_status);
  73. break;
  74. case(P_ZEROS):
  75. if((exit_status = specpzeros(dz))<0)
  76. return(exit_status);
  77. break;
  78. default:
  79. sprintf(errstr,"Unknown process in specpinfo()\n");
  80. return(PROGRAM_ERROR);
  81. }
  82. return(FINISHED);
  83. }
  84. /************************************* DO_SPECPINFO ******************************/
  85. int do_specpinfo(dataptr dz)
  86. {
  87. int exit_status;
  88. int n, minpos = -1, maxpos = -1;
  89. for(n=0;n<dz->wlength;n++) {
  90. if(dz->pitches[n]<MINPITCH)
  91. continue;
  92. if(dz->pitches[n] > dz->param[PINF_MAX]) {
  93. dz->param[PINF_MAX] = dz->pitches[n];
  94. maxpos = n;
  95. }
  96. if(dz->pitches[n] < dz->param[PINF_MIN]) {
  97. dz->param[PINF_MIN] = dz->pitches[n];
  98. minpos = n;
  99. }
  100. dz->param[PINF_MEAN] += dz->pitches[n];
  101. }
  102. dz->param[PINF_MEAN] /= (double)dz->wlength;
  103. dz->param[PINF_MAXPOS] = (double)maxpos * dz->frametime;
  104. dz->param[PINF_MINPOS] = (double)minpos * dz->frametime;
  105. if(maxpos < 0) {
  106. sprintf(errstr,"No valid pitch information found.\n");
  107. return(GOAL_FAILED);
  108. }
  109. if(minpos < 0) {
  110. sprintf(errstr,"No valid pitch below the nyquist frq found.\n");
  111. return(GOAL_FAILED);
  112. }
  113. if((exit_status = construct_screen_message(dz))<0)
  114. return(exit_status);
  115. return(FINISHED);
  116. }
  117. /***************************** SPECPZEROS *****************/
  118. int specpzeros(dataptr dz)
  119. {
  120. int n;
  121. dz->zeroset = FALSE;
  122. for(n=0;n<dz->wlength;n++) {
  123. if(dz->pitches[n]<MINPITCH) {
  124. dz->zeroset = TRUE;
  125. break;
  126. }
  127. }
  128. if(dz->zeroset)
  129. sprintf(errstr,"File contains unpitched windows.\n");
  130. else
  131. sprintf(errstr,"File does NOT contain unpitched windows.\n");
  132. return(FINISHED);
  133. }
  134. /*************************************** SPECPSEE *************************/
  135. int specpsee(dataptr dz)
  136. {
  137. int exit_status;
  138. int wc;
  139. double val;
  140. if(dz->is_transpos) {
  141. if((exit_status = prescale_transposition_data(dz))<0)
  142. return(exit_status);
  143. for(wc=0;wc<dz->wlength;wc++) {
  144. *(dz->sbufptr[0]++) = dz->transpos[wc];
  145. if(dz->sbufptr[0] >= dz->sampbuf[1]) {
  146. if((exit_status = write_exact_samps(dz->bigbuf,dz->buflen,dz))<0)
  147. return(exit_status);
  148. dz->sbufptr[0] = dz->bigbuf;
  149. }
  150. }
  151. } else {
  152. for(wc=0;wc<dz->wlength;wc++) {
  153. if((val = dz->pitches[wc] * dz->param[PSEE_SCF]) > F_MAXSAMP) {
  154. if(!dz->zeroset) {
  155. fprintf(stdout,"WARNING: output value(s) too big: truncated.\n");
  156. dz->zeroset = TRUE;
  157. }
  158. val = F_MAXSAMP;
  159. }
  160. if(val < F_MINSAMP) {
  161. if(!dz->zeroset) {
  162. fprintf(stdout,"WARNING: output value(s) too small: truncated.\n");
  163. dz->zeroset = TRUE;
  164. }
  165. val = F_MINSAMP;
  166. }
  167. *(dz->sbufptr[0]++) = (float)val;
  168. if(dz->sbufptr[0] >= dz->sampbuf[1]) {
  169. if((exit_status = write_exact_samps(dz->bigbuf,dz->buflen,dz))<0)
  170. return(exit_status);
  171. dz->sbufptr[0] = dz->bigbuf;
  172. }
  173. }
  174. }
  175. if(dz->sbufptr[0] != dz->bigbuf) {
  176. if((exit_status = write_samps(dz->bigbuf,dz->sbufptr[0] - dz->bigbuf,dz))<0)
  177. return(exit_status);
  178. }
  179. return(FINISHED);
  180. }
  181. /*************************** PRESCALE_TRANSPOSITION_DATA ********************/
  182. int prescale_transposition_data(dataptr dz)
  183. {
  184. int n;
  185. double scalefact;
  186. double mintransp = DBL_MAX;
  187. double maxtransp = -DBL_MAX;
  188. for(n=0;n<dz->wlength;n++) {
  189. if(dz->transpos[n] <= 0.0) {
  190. sprintf(errstr,"Anomaly in transposition data: prescale_transposition_data()\n");
  191. return(PROGRAM_ERROR);
  192. }
  193. dz->transpos[n] = (float)log10(dz->transpos[n]);
  194. if(dz->transpos[n] < mintransp)
  195. mintransp = dz->transpos[n];
  196. if(dz->transpos[n] > maxtransp)
  197. maxtransp = dz->transpos[n];
  198. }
  199. maxtransp = max(fabs(maxtransp),fabs(mintransp));
  200. scalefact = F_MAXSAMP/2.0/maxtransp;
  201. for(n=0;n<dz->wlength;n++)
  202. dz->transpos[n] = (float)(dz->transpos[n] * scalefact);
  203. return(FINISHED);
  204. }
  205. /************************* SPECPHEAR *************************/
  206. int specphear(dataptr dz)
  207. {
  208. #define WINDOW_AMP (0.50) /* AVOID OVERLOAD */
  209. int exit_status;
  210. double pre_totalamp, noischan_amp;
  211. double thisfrq;
  212. int n = 0;
  213. int vc;
  214. pre_totalamp = WINDOW_AMP * dz->param[PH_GAIN];
  215. noischan_amp = pre_totalamp/(double)dz->clength;
  216. memset((char *)dz->bigfbuf,0,(size_t)(dz->big_fsize * sizeof(float)));
  217. dz->flbufptr[0] = dz->bigfbuf;
  218. dz->infile->channels = dz->infile->origchans; /* setup channel count for outfile */
  219. dz->wanted = dz->infile->channels;
  220. while(n < dz->wlength) {
  221. thisfrq = (double)dz->pitches[n];
  222. if(thisfrq < 0.0) { /* NO PITCH FOUND : GENERATE NOISE */
  223. if((exit_status = generate_noise_in_buffer(noischan_amp,dz))<0)
  224. return(exit_status);
  225. } else { /* GENERATE TESTTONE AT FOUND PITCH */
  226. if((exit_status = preset_chanfrqs_to_chancentres(dz))<0)
  227. return(exit_status);
  228. if((exit_status = generate_tone_in_buffer(pre_totalamp,thisfrq,dz))<0)
  229. return(exit_status);
  230. }
  231. if(n==0) {
  232. for(vc = 0; vc < dz->wanted ; vc += 2)
  233. dz->flbufptr[0][AMPP] = 0.0f;
  234. }
  235. if((dz->flbufptr[0] += dz->wanted) >= dz->flbufptr[1]) {
  236. if((exit_status = write_exact_samps(dz->bigfbuf,dz->big_fsize,dz))<0)
  237. return(exit_status);
  238. memset((char *)dz->bigfbuf,0,(size_t)(dz->big_fsize * sizeof(float)));
  239. dz->flbufptr[0] = dz->bigfbuf;
  240. }
  241. n++;
  242. }
  243. if(dz->flbufptr[0] != dz->bigfbuf) {
  244. if((exit_status = write_samps(dz->bigfbuf,dz->flbufptr[0] - dz->bigfbuf,dz))<0)
  245. return(exit_status);
  246. }
  247. return(FINISHED);
  248. }
  249. /*************************** GENERATE_NOISE_IN_BUFFER *********************/
  250. int generate_noise_in_buffer(double noischan_amp,dataptr dz)
  251. {
  252. int cc, vc;
  253. dz->flbufptr[0][0] = (float)noischan_amp;
  254. dz->flbufptr[0][1] = (float)(drand48() * dz->halfchwidth);
  255. for(cc = 1, vc = 2; cc < dz->clength-1; cc++, vc += 2) {
  256. dz->flbufptr[0][FREQ] = (float)((drand48() * dz->chwidth) + dz->windowbuf[CHBOT][cc]);
  257. dz->flbufptr[0][AMPP] = (float)noischan_amp;
  258. }
  259. dz->flbufptr[0][FREQ] = (float)((drand48() * dz->halfchwidth) + dz->windowbuf[CHBOT][cc]);
  260. dz->flbufptr[0][AMPP] = (float)noischan_amp;
  261. return(FINISHED);
  262. }
  263. /********************** GENERATE_TONE_IN_BUFFER ***************************/
  264. int generate_tone_in_buffer(double pre_totalamp,double thisfrq,dataptr dz)
  265. {
  266. int exit_status;
  267. int cc, vc, m, ampadjusted = 0;
  268. int lastvc = -1;
  269. double post_totalamp;
  270. for(m=0;m<PARTIALS_IN_TEST_TONE;m++) {
  271. cc = (int)((thisfrq + dz->halfchwidth)/dz->chwidth); /* TRUNCATE */
  272. vc = cc * 2;
  273. if(vc != lastvc) { /* AVOID OVERWRITING ALREADY GENERATED LOWER PARTIALS */
  274. dz->flbufptr[0][AMPP] = dz->windowbuf[TESTPAMP][m];
  275. dz->flbufptr[0][FREQ] = (float)thisfrq;
  276. }
  277. lastvc = vc;
  278. if((thisfrq = thisfrq * 2.0) > dz->nyquist) {
  279. post_totalamp = (double)dz->windowbuf[TOTPAMP][m];
  280. /* THIS NORMALISATION DOESN'T QUITE WORK */
  281. if((exit_status = normalise(pre_totalamp,post_totalamp,dz))<0)
  282. return(exit_status);
  283. ampadjusted = 1; /* IF PITCH IS LESS THAN CHAN SPACING */
  284. break; /* BUT THAT'S MINOR AESTHETIC QUIBBLE ONLY */
  285. }
  286. }
  287. if(!ampadjusted) {
  288. post_totalamp = (double)dz->windowbuf[TOTPAMP][PARTIALS_IN_TEST_TONE-1];
  289. if((exit_status = normalise(pre_totalamp,post_totalamp,dz))<0)
  290. return(exit_status);
  291. }
  292. return(FINISHED);
  293. }
  294. /**************************** PRESET_CHANFRQS_TO_CHANCENTRES **********************
  295. *
  296. * Preset all frqs to centre of channels.
  297. */
  298. int preset_chanfrqs_to_chancentres(dataptr dz)
  299. {
  300. int cc, vc;
  301. dz->flbufptr[0][1] = (float)(dz->halfchwidth/2.0);
  302. for(cc = 1, vc = 2; cc < dz->clength-1; cc++, vc += 2)
  303. dz->flbufptr[0][FREQ] = (float)(dz->windowbuf[CHBOT][cc] + dz->halfchwidth);
  304. dz->flbufptr[0][FREQ]=(float)(dz->windowbuf[CHBOT][dz->clength-1]+(dz->halfchwidth/2.0));
  305. return(FINISHED);
  306. }
  307. /****************************** SPECPWRITE *********************************/
  308. int specpwrite(dataptr dz)
  309. {
  310. int exit_status;
  311. int brkcnt;
  312. if((dz->parray[PW_BRK] = (double *)malloc(dz->wlength * 2 * sizeof(double)))==NULL) {
  313. sprintf(errstr,"INSUFFICIENT MEMORY for pitch brkpnt array.\n");
  314. return(MEMORY_ERROR);
  315. }
  316. if(dz->is_transpos) {
  317. if((exit_status = convert_pch_or_transpos_data_to_brkpnttable(&brkcnt,dz->transpos,dz->frametime,PW_BRK,dz))<0)
  318. return(exit_status);
  319. } else {
  320. if((exit_status = convert_pch_or_transpos_data_to_brkpnttable(&brkcnt,dz->pitches,dz->frametime,PW_BRK,dz))<0)
  321. return(exit_status);
  322. }
  323. return write_brkfile(dz->fp,brkcnt,PW_BRK,dz);
  324. }
  325. /****************************** CONSTRUCT_SCREEN_MESSAGE *********************************/
  326. int construct_screen_message(dataptr dz)
  327. {
  328. int exit_status;
  329. int oct = 0;
  330. double z1, z2, z3, z4, z5;
  331. if((exit_status = hztomidi(&z1,dz->param[PINF_MAX]))<0)
  332. return(exit_status);
  333. if((exit_status = hztomidi(&z2,dz->param[PINF_MIN]))<0)
  334. return(exit_status);
  335. if((exit_status = hztomidi(&z3,dz->param[PINF_MEAN]))<0)
  336. return(exit_status);
  337. if((exit_status = hztomidi(&z4,dz->param[PINF_MAX]))<0)
  338. return(exit_status);
  339. if((exit_status = hztomidi(&z5,dz->param[PINF_MIN]))<0)
  340. return(exit_status);
  341. z4 -= z5;
  342. if(z4 > 12.0) {
  343. oct = (int)(z4/12.0); /* TRUNCATE */
  344. z4 -= (double)(oct * 12);
  345. }
  346. if(oct > 0) {
  347. sprintf(errstr,"MAX PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n"
  348. "MIN PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n"
  349. "MEAN PITCH: %.2lfHZ\tMIDI : %.2lf\n\n"
  350. "TOTAL RANGE: %d OCTAVES and %.2lf SEMITONES\n",
  351. dz->param[PINF_MAX],z1,dz->param[PINF_MAXPOS],dz->param[PINF_MIN],z2,dz->param[PINF_MINPOS],
  352. dz->param[PINF_MEAN],z3, oct, z4);
  353. } else {
  354. sprintf(errstr,"MAX PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n"
  355. "MIN PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n"
  356. "MEAN PITCH: %.2lfHZ\tMIDI : %.2lf\n\n"
  357. "TOTAL RANGE: %.2lf SEMITONES\n",
  358. dz->param[PINF_MAX],z1,dz->param[PINF_MAXPOS],dz->param[PINF_MIN],z2,dz->param[PINF_MINPOS],
  359. dz->param[PINF_MEAN],z3,z4);
  360. }
  361. return(FINISHED);
  362. }