notchinvert.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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. /*
  22. * Take a set of amp-frq data in the correct range,
  23. * find the notches in the spectrum.
  24. * Create a new spectrum by inverting these notches to become peaks
  25. */
  26. #define PSEUDOCENT (1.0009) // approx 1/64th of a tone
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <structures.h>
  30. #include <tkglobals.h>
  31. #include <pnames.h>
  32. #include <filetype.h>
  33. #include <processno.h>
  34. #include <modeno.h>
  35. #include <logic.h>
  36. #include <globcon.h>
  37. #include <cdpmain.h>
  38. #include <math.h>
  39. #include <mixxcon.h>
  40. #include <osbind.h>
  41. #include <science.h>
  42. #include <ctype.h>
  43. #include <sfsys.h>
  44. #include <string.h>
  45. #include <srates.h>
  46. int sloom = 0;
  47. int sloombatch = 0;
  48. const char* cdp_version = "6.1.0";
  49. //CDP LIB REPLACEMENTS
  50. //static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q);
  51. static int handle_the_special_data(FILE *fpi, double **parray, int *itemcnt);
  52. static int test_the_special_data(double *parray, int itemcnt, double nyquist);
  53. static int invnotch(double *parray,int itemcnt,double *outarray,double minnotch);
  54. static int get_float_with_e_from_within_string(char **str,double *val);
  55. /**************************************** MAIN *********************************************/
  56. int main(int argc,char *argv[])
  57. {
  58. FILE *fpi, *fpo;
  59. int k;
  60. int exit_status;
  61. double *parray, *outarray;
  62. int itemcnt, srate;
  63. double minnotch = 0.0, nyquist;
  64. char temp[200], temp2[200];
  65. if(argc < 4 || argc > 5) {
  66. usage1();
  67. return(FAILED);
  68. }
  69. if(argc == 5) {
  70. if(sscanf(argv[4],"%lf",&minnotch) != 1) {
  71. fprintf(stderr,"CANNOT READ POINTCNT (%s)\n",argv[3]);
  72. return(FAILED);
  73. }
  74. if(minnotch > 1.0 || minnotch < 0.0) {
  75. fprintf(stderr,"INVALID MINIMUM NOTCH %s (range 0 - 1)\n",argv[3]);
  76. return(FAILED);
  77. }
  78. }
  79. if(sscanf(argv[3],"%d",&srate) != 1) {
  80. fprintf(stderr,"CANNOT READ SAMPLERATE (%s)\n",argv[3]);
  81. return(FAILED);
  82. }
  83. if(srate < 44100 || BAD_SR(srate)) {
  84. fprintf(stderr,"INVALID SAMPLE RATE ENTERED (44100,48000,88200,96000 only).\n");
  85. return(FAILED);
  86. }
  87. nyquist = (double)(srate/2);
  88. if((fpi = fopen(argv[1],"r")) == NULL) {
  89. fprintf(stderr,"CANNOT OPEN DATAFILE %s\n",argv[1]);
  90. return(FAILED);
  91. }
  92. if((exit_status = handle_the_special_data(fpi,&parray,&itemcnt))<0)
  93. return(FAILED);
  94. if((exit_status = test_the_special_data(parray,itemcnt,nyquist))<0)
  95. return(FAILED);
  96. if((outarray = (double *)malloc(itemcnt * sizeof(double)))==NULL) {
  97. fprintf(stderr,"INSUFFICIENT MEMORY for input data.\n");
  98. return(MEMORY_ERROR);
  99. }
  100. if((fpo = fopen(argv[2],"w")) == NULL) {
  101. fprintf(stderr,"CANNOT OPEN OUTPUT DATAFILE %s\n",argv[2]);
  102. return(FAILED);
  103. }
  104. if((exit_status = invnotch(parray,itemcnt,outarray,minnotch)) < 0)
  105. return(FAILED);
  106. k = 0;
  107. for(k = 0;k < itemcnt;k+=2) {
  108. sprintf(temp,"%lf",outarray[k]);
  109. sprintf(temp2,"%lf",outarray[k+1]);
  110. strcat(temp2,"\n");
  111. strcat(temp,"\t");
  112. strcat(temp,temp2);
  113. fputs(temp,fpo);
  114. }
  115. if(fclose(fpo)<0) {
  116. fprintf(stderr,"WARNING: Failed to close output data file %s.\n",argv[2]);
  117. }
  118. return(SUCCEEDED);
  119. }
  120. /******************************** USAGE1 ********************************/
  121. int usage1(void)
  122. {
  123. fprintf(stderr,
  124. "USAGE: notchinvert datafile outdatafile srate [minnotch]\n"
  125. "\n"
  126. "Invert notches in a spectrum.\n"
  127. "\n"
  128. "DATAFILE textfile of frq/amp pairs.\n"
  129. "OUTDATAFILE inverted notches as frq/amp pairs.\n"
  130. "MINNOTCH min depth of notch to qualify as true notch (Range 0-1).\n"
  131. "\n");
  132. return(USAGE_ONLY);
  133. }
  134. /************************** HANDLE_THE_SPECIAL_DATA **********************************/
  135. int handle_the_special_data(FILE *fpi, double **parray, int *itemcnt)
  136. {
  137. int cnt;
  138. double *p, dummy;
  139. char temp[200], *q;
  140. cnt = 0;
  141. p = &dummy;
  142. while(fgets(temp,200,fpi)==temp) {
  143. q = temp;
  144. if(*q == ';') // Allow comments in file
  145. continue;
  146. while(get_float_with_e_from_within_string(&q,p))
  147. cnt++;
  148. }
  149. if(ODD(cnt)) {
  150. fprintf(stderr,"Data not paired correctly in input data file\n");
  151. return(DATA_ERROR);
  152. }
  153. if(cnt == 0) {
  154. fprintf(stderr,"No data in input data file\n");
  155. return(DATA_ERROR);
  156. }
  157. if((*parray = (double *)malloc(cnt * sizeof(double)))==NULL) {
  158. fprintf(stderr,"INSUFFICIENT MEMORY for input data.\n");
  159. return(MEMORY_ERROR);
  160. }
  161. fseek(fpi,0,0);
  162. p = *parray;
  163. while(fgets(temp,200,fpi)==temp) {
  164. q = temp;
  165. if(*q == ';') // Allow comments in file
  166. continue;
  167. while(get_float_with_e_from_within_string(&q,p)) {
  168. p++;
  169. }
  170. }
  171. if(fclose(fpi)<0) {
  172. fprintf(stderr,"WARNING: Failed to close input data file.\n");
  173. }
  174. *itemcnt = cnt;
  175. return(FINISHED);
  176. }
  177. /************************** TEST_THE_SPECIAL_DATA **********************************/
  178. int test_the_special_data(double *parray, int itemcnt, double nyquist)
  179. {
  180. double *p;
  181. int isamp = 0, linecnt = 1;
  182. p = parray;
  183. while(linecnt <= itemcnt/2) {
  184. if(isamp) {
  185. if(*p < 0.0 || *p > 1.0) {
  186. fprintf(stderr,"Amp (%lf) out of range (0-1) at line %d in datafile.\n",*p,linecnt);
  187. return(DATA_ERROR);
  188. }
  189. } else {
  190. if(*p < 0.0 || *p > nyquist) {
  191. fprintf(stderr,"Frq (%lf) out of range (0 - %lf) at line %d in datafile.\n",*p,nyquist,linecnt);
  192. return(DATA_ERROR);
  193. }
  194. }
  195. if(!isamp)
  196. linecnt++;
  197. isamp = !isamp;
  198. p++;
  199. }
  200. return(FINISHED);
  201. }
  202. /************************** INVNOTCH **********************************/
  203. int invnotch(double *parray,int itemcnt,double *outarray,double minnotch)
  204. {
  205. int ampat, trofampat, pkampbelowat, pkampaboveat, nextpkat, writeat, j;
  206. double amp, lastamp, ampstep, lastampstep, belowstep, abovestep, notchdepth, subtractor;
  207. double *pkbefore, *pkafter, *notch;
  208. int trofcnt, badnotches, jj, kk;
  209. int *pkbeforeat, *notchat;
  210. memset((char *)outarray,0,itemcnt * sizeof(double));
  211. /* FIND PEAKS AND TROUGHS */
  212. lastamp = parray[1];
  213. lastampstep = 0;
  214. ampat = 3;
  215. trofcnt = 0;
  216. while(ampat < itemcnt) {
  217. amp = parray[ampat];
  218. ampstep = amp - lastamp;
  219. if(ampstep < 0) {
  220. if(lastampstep > 0) { // falling after rise = peak
  221. outarray[ampat-2] = 1.0; // peak
  222. }
  223. lastampstep = ampstep;
  224. } else if(ampstep > 0) {
  225. if(lastampstep < 0) { // rising after fall = trough
  226. outarray[ampat-2] = -1.0; // trough
  227. trofcnt++;
  228. }
  229. lastampstep = ampstep;
  230. } // else, if flat : lastampstep not updated
  231. lastamp = amp; // saddle points are thus ignored, while flat peaks or troughs are spotted
  232. ampat += 2;
  233. }
  234. if(trofcnt == 0) {
  235. fprintf(stderr,"NO NOTCHES FOUND\n");
  236. for(j = 0; j < itemcnt; j+=2) {
  237. outarray[j] = parray[j];
  238. outarray[j+1] = 0.0;
  239. }
  240. return FINISHED;
  241. }
  242. if((pkbefore = (double *)malloc((trofcnt + 6) * sizeof(double)))==NULL) {
  243. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (1).\n");
  244. return(MEMORY_ERROR);
  245. }
  246. if((pkafter = (double *)malloc((trofcnt + 6) * sizeof(double)))==NULL) {
  247. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (2).\n");
  248. return(MEMORY_ERROR);
  249. }
  250. if((pkbeforeat = (int *)malloc((trofcnt + 6) * sizeof(int)))==NULL) {
  251. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (1).\n");
  252. return(MEMORY_ERROR);
  253. }
  254. if((notch = (double *)malloc((trofcnt + 6) * sizeof(double)))==NULL) {
  255. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (2).\n");
  256. return(MEMORY_ERROR);
  257. }
  258. if((notchat = (int *)malloc((trofcnt + 6) * sizeof(int)))==NULL) {
  259. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (2).\n");
  260. return(MEMORY_ERROR);
  261. }
  262. trofcnt = 0;
  263. ampat = 1;
  264. pkampbelowat = -1; // position of peak before trough
  265. pkampaboveat = -1; // position of peak after trough
  266. trofampat = -1; // position of trough
  267. /* NOTE LEVELS BEFORE AND AFTER NOTCHES AND MARK BAD NOTCHES */
  268. badnotches = 0;
  269. while(ampat < itemcnt) {
  270. amp = outarray[ampat];
  271. if(amp < 0.0) {
  272. if(pkampbelowat < 0) {
  273. pkampbelowat = 1;
  274. pkbefore[trofcnt] = parray[pkampbelowat];
  275. pkbeforeat[trofcnt] = pkampbelowat;
  276. }
  277. trofampat = ampat;
  278. notch[trofcnt] = parray[ampat];
  279. notchat[trofcnt] = ampat;
  280. } else if(amp > 0.0) { // found peak
  281. if(trofampat < 0) { // if not yet found trof, this is the peak below the trof
  282. pkampbelowat = ampat;
  283. pkbefore[trofcnt] = parray[pkampbelowat];
  284. pkbeforeat[trofcnt] = pkampbelowat;
  285. } else { // otherwise, its peak above trof : we now have complete notch
  286. pkampaboveat = ampat;
  287. pkafter[trofcnt] = parray[pkampaboveat];
  288. belowstep = pkbefore[trofcnt] - parray[trofampat];
  289. abovestep = pkafter[trofcnt] - parray[trofampat];
  290. notchdepth = min(belowstep,abovestep);
  291. if(notchdepth < minnotch)
  292. badnotches = 1;
  293. trofcnt++;
  294. pkampbelowat = pkampaboveat; // move to next notch
  295. pkbefore[trofcnt] = parray[pkampbelowat];
  296. pkbeforeat[trofcnt] = pkampbelowat;
  297. pkampaboveat = -1;
  298. trofampat = -1;
  299. }
  300. }
  301. ampat += 2; // if no peak found after last trough ..
  302. } // and last trof is not at very end (shoulf be impossible)
  303. if(trofampat >= 0 && (trofampat != itemcnt-1) && (pkampaboveat < 0)) {
  304. pkampaboveat = itemcnt - 1; // set peak to top edge of spectrum
  305. pkafter[trofcnt] = parray[pkampaboveat];
  306. belowstep = pkbefore[trofcnt] - parray[trofampat];
  307. abovestep = pkafter[trofcnt] - parray[trofampat];
  308. notchdepth = min(belowstep,abovestep);
  309. if(notchdepth < minnotch) // Mark notches that are not deep enough
  310. badnotches = 1;
  311. trofcnt++;
  312. pkbefore[trofcnt] = parray[pkampaboveat]; // Extra "pkbefore" after last notch
  313. pkbeforeat[trofcnt] = pkampaboveat;
  314. }
  315. /* ELIMINATE ADJACENT BAD NOTCHES */
  316. if(badnotches) {
  317. for(kk = 0;kk < trofcnt;kk++) { // x x
  318. if(pkbefore[kk] - notch[kk] < minnotch) { // x o x
  319. if((kk>0) && (pkbefore[kk] - notch[kk-1] < minnotch)) { // x x x x
  320. //ELIMINATE PEAK // x o
  321. outarray[pkbeforeat[kk]] = 0.0;
  322. // KEEP DEEPEST NOTCH
  323. if(notch[kk] <= notch[kk-1]) { // x x
  324. outarray[notchat[kk-1]] = 0.0; // x o x
  325. notch[kk-1] = notch[kk]; // x x x x
  326. notchat[kk-1]= notchat[kk]; // + o
  327. } else {
  328. outarray[notchat[kk]] = 0.0;
  329. }
  330. for(jj = kk+1;jj < trofcnt; jj++) {
  331. pkbefore[jj-1] = pkbefore[jj];
  332. pkbeforeat[jj-1] = pkbeforeat[jj];
  333. notch[jj-1] = notch[jj];
  334. notchat[jj-1] = notchat[jj];
  335. }
  336. pkbefore[jj-1] = pkbefore[jj];
  337. pkbeforeat[jj-1] = pkbeforeat[jj];
  338. } else if(pkbefore[kk+1] - notch[kk] < minnotch) { // o +
  339. //ELIMINATE NOTCH // x x x x
  340. outarray[notchat[kk]] = 0.0; // x o x
  341. //ELIMINATE LOWEST PEAK // x x
  342. if(pkbefore[kk] >= pkbefore[kk+1]) {
  343. outarray[pkbeforeat[kk+1]] = 0.0;
  344. if(kk < trofcnt-1) {
  345. notch[kk] = notch[kk+1];
  346. notchat[kk] = notchat[kk+1];
  347. }
  348. for(jj = kk+2;jj < trofcnt; jj++) {
  349. pkbefore[jj-1] = pkbefore[jj];
  350. pkbeforeat[jj-1] = pkbeforeat[jj];
  351. notch[jj-1] = notch[jj];
  352. notchat[jj-1] = notchat[jj];
  353. }
  354. pkbefore[jj-1] = pkbefore[jj];
  355. pkbeforeat[jj-1] = pkbeforeat[jj];
  356. } else {
  357. outarray[pkbeforeat[kk]] = 0.0;
  358. for(jj = kk+1;jj < trofcnt; jj++) {
  359. pkbefore[jj-1] = pkbefore[jj];
  360. pkbeforeat[jj-1] = pkbeforeat[jj];
  361. notch[jj-1] = notch[jj];
  362. notchat[jj-1] = notchat[jj];
  363. }
  364. pkbefore[jj-1] = pkbefore[jj];
  365. pkbeforeat[jj-1] = pkbeforeat[jj];
  366. }
  367. } else {
  368. //ELIMINATE PEAK BEFORE AND NOTCH // x
  369. outarray[pkbeforeat[kk]] = 0.0; // o x
  370. outarray[notchat[kk]] = 0.0; // x x x
  371. for(jj = kk+1;jj < trofcnt; jj++) { // x o
  372. pkbefore[jj-1] = pkbefore[jj]; // x
  373. pkbeforeat[jj-1] = pkbeforeat[jj];
  374. notch[jj-1] = notch[jj];
  375. notchat[jj-1] = notchat[jj];
  376. }
  377. pkbefore[jj-1] = pkbefore[jj];
  378. pkbeforeat[jj-1] = pkbeforeat[jj];
  379. }
  380. kk--;
  381. trofcnt--;
  382. } else if(pkbefore[kk+1] - notch[kk] < minnotch) { // x
  383. //ELIMINATE PEAK AFTER AND NOTCH // x o
  384. outarray[pkbeforeat[kk+1]] = 0.0; // x x x
  385. outarray[notchat[kk]] = 0.0; // o x
  386. if(kk < trofcnt-1) { // x
  387. notch[kk] = notch[kk+1];
  388. notchat[kk] = notchat[kk+1];
  389. }
  390. for(jj = kk+2;jj < trofcnt; jj++) {
  391. pkbefore[jj-1] = pkbefore[jj];
  392. pkbeforeat[jj-1] = pkbeforeat[jj];
  393. notch[jj-1] = notch[jj];
  394. notchat[jj-1] = notchat[jj];
  395. }
  396. pkbefore[jj-1] = pkbefore[jj];
  397. pkbeforeat[jj-1] = pkbeforeat[jj];
  398. kk--;
  399. trofcnt--;
  400. }
  401. }
  402. }
  403. writeat = 0; // position of write to output
  404. kk = 0;
  405. while(writeat < pkbeforeat[0]-1) { // zero output before 1st peak
  406. outarray[writeat] = parray[writeat];
  407. writeat++;
  408. outarray[writeat] = 0.0;
  409. writeat++;
  410. }
  411. for(kk = 0;kk < trofcnt;kk++) {
  412. nextpkat = pkbeforeat[kk+1] - 1; // nextpkat points to the PAIR of values: pkbeforeat points to its amplitude
  413. belowstep = pkbefore[kk] - notch[kk];
  414. abovestep = pkbefore[kk+1] - notch[kk];
  415. notchdepth = min(belowstep,abovestep);
  416. if(belowstep < abovestep)
  417. subtractor = pkbefore[kk];
  418. else
  419. subtractor = pkbefore[kk+1];
  420. while(writeat < nextpkat) {
  421. outarray[writeat] = parray[writeat];
  422. writeat++;
  423. outarray[writeat] = min(parray[writeat] - subtractor,0.0);
  424. outarray[writeat] = -outarray[writeat];
  425. writeat++;
  426. }
  427. }
  428. while(writeat < itemcnt) { // zero output after last peak
  429. outarray[writeat] = parray[writeat];
  430. writeat++;
  431. outarray[writeat] = 0.0;
  432. writeat++;
  433. }
  434. return(FINISHED);
  435. }
  436. /************************** GET_FLOAT_WITH_E_FROM_WITHIN_STRING **************************
  437. * takes a pointer TO A POINTER to a string. If it succeeds in finding
  438. * a float it returns the float value (*val), and it's new position in the
  439. * string (*str).
  440. */
  441. int get_float_with_e_from_within_string(char **str,double *val)
  442. {
  443. char *p, *valstart;
  444. int decimal_point_cnt = 0, has_digits = 0, has_e = 0, lastchar = 0;
  445. p = *str;
  446. while(isspace(*p))
  447. p++;
  448. valstart = p;
  449. switch(*p) {
  450. case('-'): break;
  451. case('.'): decimal_point_cnt=1; break;
  452. default:
  453. if(!isdigit(*p))
  454. return(FALSE);
  455. has_digits = TRUE;
  456. break;
  457. }
  458. p++;
  459. while(!isspace(*p) && *p!=NEWLINE && *p!=ENDOFSTR) {
  460. if(isdigit(*p))
  461. has_digits = TRUE;
  462. else if(*p == 'e') {
  463. if(has_e || !has_digits)
  464. return(FALSE);
  465. has_e = 1;
  466. } else if(*p == '-') {
  467. if(!has_e || (lastchar != 'e'))
  468. return(FALSE);
  469. } else if(*p == '.') {
  470. if(has_e || (++decimal_point_cnt>1))
  471. return(FALSE);
  472. } else
  473. return(FALSE);
  474. lastchar = *p;
  475. p++;
  476. }
  477. if(!has_digits || sscanf(valstart,"%lf",val)!=1)
  478. return(FALSE);
  479. *str = p;
  480. return(TRUE);
  481. }