smooth.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. * Take a set of amp-frq data in the correct range,
  3. * and use linear interpolation to replot curve to cover
  4. * every 1/64 tone over whole range.
  5. * Where, frq ratio between adjacent chans becomes < 1/64 tone
  6. * use chan centre frqs.
  7. */
  8. #define PSEUDOCENT (1.0009) // approx 1/64th of a tone
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <structures.h>
  12. #include <tkglobals.h>
  13. #include <pnames.h>
  14. #include <filetype.h>
  15. #include <processno.h>
  16. #include <modeno.h>
  17. #include <logic.h>
  18. #include <globcon.h>
  19. #include <cdpmain.h>
  20. #include <math.h>
  21. #include <mixxcon.h>
  22. #include <osbind.h>
  23. #include <science.h>
  24. #include <ctype.h>
  25. #include <sfsys.h>
  26. #include <string.h>
  27. #include <srates.h>
  28. int sloom = 0;
  29. int sloombatch = 0;
  30. const char* cdp_version = "6.1.0";
  31. char errstr[2400]; //RWD need this
  32. //CDP LIB REPLACEMENTS
  33. static int allocate_output_array(double **outarray, int *outcnt, double chwidth, double halfchwidth, double nyquist);
  34. static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q);
  35. static int handle_the_special_data(FILE *fpi, double **parray, int *itemcnt);
  36. static int test_the_special_data(double *parray, int itemcnt, double nyquist);
  37. static int smooth(double *parray,int itemcnt,double *outarray,int *outcnt,double chwidth,double halfchwidth,double nyquist,int arraycnt);
  38. static int dove(double *parray,int itemcnt,double *outarray,int outcnt);
  39. static int read_value_from_array(double *outval,double thisfrq,double *brk,double **brkptr,int brksize,double *firstval,double *lastval,double *lastind,int *brkinit);
  40. static int get_float_with_e_from_within_string(char **str,double *val);
  41. /**************************************** MAIN *********************************************/
  42. int main(int argc,char *argv[])
  43. {
  44. FILE *fpi, *fpo;
  45. int k, OK = 0, dovetail = 0;
  46. int exit_status, srate, pointcnt, clength;
  47. double chwidth, halfchwidth, nyquist, *parray, *outarray;
  48. int itemcnt, outcnt, arraycnt;
  49. char temp[200], temp2[200];
  50. if(argc < 5 || argc > 6) {
  51. usage1();
  52. return(FAILED);
  53. }
  54. if((fpi = fopen(argv[1],"r")) == NULL) {
  55. fprintf(stderr,"CANNOT OPEN DATAFILE %s\n",argv[1]);
  56. return(FAILED);
  57. }
  58. if((exit_status = handle_the_special_data(fpi,&parray,&itemcnt))<0)
  59. return(FAILED);
  60. arraycnt = itemcnt/2;
  61. if(sscanf(argv[3],"%d",&pointcnt) != 1) {
  62. fprintf(stderr,"CANNOT READ POINTCNT (%s)\n",argv[3]);
  63. return(FAILED);
  64. }
  65. OK = 0;
  66. k = 1;
  67. while(k < pointcnt) {
  68. k *= 2;
  69. if(k == pointcnt){
  70. OK= 1;
  71. break;
  72. }
  73. }
  74. if(!OK) {
  75. fprintf(stderr,"ANALYSIS POINTS PARAMETER MUST BE A POWER OF TWO.\n");
  76. return(FAILED);
  77. }
  78. if(sscanf(argv[4],"%d",&srate) != 1) {
  79. fprintf(stderr,"CANNOT READ SAMPLE RATE (%s)\n",argv[3]);
  80. return(FAILED);
  81. }
  82. if(srate < 44100 || BAD_SR(srate)) {
  83. fprintf(stderr,"INVALID SAMPLE RATE ENTERED (44100,48000,88200,96000 only).\n");
  84. return(DATA_ERROR);
  85. }
  86. if(argc == 6) {
  87. if(strcmp(argv[5],"-s")) {
  88. fprintf(stderr,"UNKNOWN FINAL PARAMETER (%s).\n",argv[5]);
  89. return(DATA_ERROR);
  90. }
  91. dovetail = 1;
  92. }
  93. clength = (pointcnt + 2)/2;
  94. nyquist = (double)(srate / 2);
  95. chwidth = nyquist/(double)clength;
  96. halfchwidth = chwidth / 2;
  97. if((exit_status = test_the_special_data(parray,itemcnt,nyquist))<0)
  98. return(FAILED);
  99. if((exit_status = allocate_output_array(&outarray,&outcnt,chwidth,halfchwidth,nyquist))<0)
  100. return(FAILED);
  101. if((fpo = fopen(argv[2],"w")) == NULL) {
  102. fprintf(stderr,"CANNOT OPEN OUTPUT DATAFILE %s\n",argv[2]);
  103. return(FAILED);
  104. }
  105. if((exit_status = smooth(parray,itemcnt,outarray,&outcnt,chwidth,halfchwidth,nyquist,arraycnt)) < 0)
  106. return(FAILED);
  107. if(dovetail) {
  108. if((exit_status = dove(parray,itemcnt,outarray,outcnt)) < 0)
  109. return(FAILED);
  110. }
  111. k = 0;
  112. for(k = 0;k < outcnt;k+=2) {
  113. sprintf(temp,"%lf",outarray[k]);
  114. sprintf(temp2,"%lf",outarray[k+1]);
  115. strcat(temp2,"\n");
  116. strcat(temp,"\t");
  117. strcat(temp,temp2);
  118. fputs(temp,fpo);
  119. }
  120. if(fclose(fpo)<0) {
  121. fprintf(stderr,"WARNING: Failed to close output data file %s.\n",argv[2]);
  122. }
  123. return(SUCCEEDED);
  124. }
  125. /******************************** USAGE1 ********************************/
  126. int usage1(void)
  127. {
  128. fprintf(stderr,
  129. "USAGE: smooth datafile outdatafile pointcnt srate [-s]\n"
  130. "\n"
  131. "Generate smoothed curve from input data re spectrum.\n"
  132. "\n"
  133. "DATAFILE textfile of frq/amp pairs.\n"
  134. "OUTDATAFILE textfile of smoothed data.\n"
  135. "POINTCNT no of analysis points required in handling data.\n"
  136. "SRATE samplerate of eventual sound output.\n"
  137. "-s if spectral amp falls to zero before the nyquist,\n"
  138. " keep zeroed end of spectrum at zero.\n."
  139. "\n");
  140. return(USAGE_ONLY);
  141. }
  142. /************************** HANDLE_THE_SPECIAL_DATA **********************************/
  143. int handle_the_special_data(FILE *fpi, double **parray, int *itemcnt)
  144. {
  145. int cnt, linecnt;
  146. double *p, dummy;
  147. char temp[200], *q;
  148. cnt = 0;
  149. p = &dummy;
  150. while(fgets(temp,200,fpi)==temp) {
  151. q = temp;
  152. if(*q == ';') // Allow comments in file
  153. continue;
  154. while(get_float_with_e_from_within_string(&q,p))
  155. cnt++;
  156. }
  157. if(ODD(cnt)) {
  158. fprintf(stderr,"Data not paired correctly in input data file\n");
  159. return(DATA_ERROR);
  160. }
  161. if(cnt == 0) {
  162. fprintf(stderr,"No data in input data file\n");
  163. return(DATA_ERROR);
  164. }
  165. if((*parray = (double *)malloc(cnt * sizeof(double)))==NULL) {
  166. fprintf(stderr,"INSUFFICIENT MEMORY for input data.\n");
  167. return(MEMORY_ERROR);
  168. }
  169. fseek(fpi,0,0);
  170. linecnt = 1;
  171. p = *parray;
  172. while(fgets(temp,200,fpi)==temp) {
  173. q = temp;
  174. if(*q == ';') // Allow comments in file
  175. continue;
  176. while(get_float_with_e_from_within_string(&q,p)) {
  177. p++;
  178. }
  179. linecnt++;
  180. }
  181. if(fclose(fpi)<0) {
  182. fprintf(stderr,"WARNING: Failed to close input data file.\n");
  183. }
  184. *itemcnt = cnt;
  185. return(FINISHED);
  186. }
  187. /************************** TEST_THE_SPECIAL_DATA **********************************/
  188. int test_the_special_data(double *parray, int itemcnt, double nyquist)
  189. {
  190. double *p;
  191. int isamp = 0, linecnt = 1;
  192. p = parray;
  193. while(linecnt <= itemcnt/2) {
  194. if(isamp) {
  195. if(*p < 0.0 || *p > 1.0) {
  196. fprintf(stderr,"Amp (%lf) out of range (0-1) at line %d in datafile.\n",*p,linecnt);
  197. return(DATA_ERROR);
  198. }
  199. } else {
  200. if(*p < 0.0 || *p > nyquist) {
  201. fprintf(stderr,"Frq (%lf) out of range (0 - %lf) at line %d in datafile.\n",*p,nyquist,linecnt);
  202. return(DATA_ERROR);
  203. }
  204. }
  205. if(!isamp)
  206. linecnt++;
  207. isamp = !isamp;
  208. p++;
  209. }
  210. return(FINISHED);
  211. }
  212. /************************** ALLOCATE_OUTPUT_ARRAY **********************************/
  213. int allocate_output_array(double **outarray,int *outcnt,double chwidth,double halfchwidth,double nyquist)
  214. {
  215. int outsize = 1; // Count initial halfwidht channel
  216. double lastlofrq, lofrq = halfchwidth;
  217. while(lofrq <= nyquist) {
  218. outsize++;
  219. lastlofrq = lofrq;
  220. lofrq *= PSEUDOCENT;
  221. if(lofrq - lastlofrq >= chwidth) // Once chan separation is > chwidth
  222. lofrq = lastlofrq + chwidth; // Just set 1 value per channel
  223. }
  224. outsize += 64; // SAFETY
  225. outsize *= 2;
  226. if((*outarray = (double *)malloc(outsize * sizeof(double)))==NULL) {
  227. fprintf(stderr,"INSUFFICIENT MEMORY for input data.\n");
  228. return(MEMORY_ERROR);
  229. }
  230. *outcnt = outsize;
  231. return( FINISHED);
  232. }
  233. /************************** SMOOTH **********************************/
  234. int smooth(double *parray,int itemcnt,double *outarray,int *outcnt,double chwidth,double halfchwidth,double nyquist,int arraycnt)
  235. {
  236. int exit_status;
  237. int k = 0, hi = 0;
  238. double lastlofrq, lofrq = halfchwidth, thisamp;
  239. double *brkptr = parray;
  240. int brksize = itemcnt/2;
  241. double firstval,lastval,lastind;
  242. int brkinit = 0;
  243. outarray[k] = 0.0;
  244. outarray[k+1] = 0.0;
  245. k = 2;
  246. while(lofrq < nyquist) {
  247. if(k >= *outcnt) {
  248. fprintf(stderr,"OUT OF MEMORY IN OUTPUT ARRAY.\n");
  249. return(MEMORY_ERROR);
  250. }
  251. if((exit_status = read_value_from_array(&thisamp,lofrq,parray,&brkptr,brksize,&firstval,&lastval,&lastind,&brkinit))<0)
  252. return(exit_status);
  253. outarray[k] = lofrq;
  254. outarray[k+1] = thisamp;
  255. lastlofrq = lofrq;
  256. lofrq *= PSEUDOCENT;
  257. if(lofrq - lastlofrq >= chwidth) // Once chan separation is < PSEUDOCENT
  258. lofrq = lastlofrq + chwidth; // Just set 1 value per channel
  259. k += 2;
  260. }
  261. outarray[k++] = nyquist;
  262. outarray[k++] = 0.0;
  263. *outcnt = k;
  264. if(outarray[0] == 0.0 && outarray[2] == 0.0) { // Eliminate any duplication of zero start frq
  265. k = 0;
  266. hi = 2;
  267. while(hi < *outcnt) {
  268. outarray[k] = outarray[hi];
  269. k++;
  270. hi++;
  271. }
  272. *outcnt = k;
  273. }
  274. return(FINISHED);
  275. }
  276. /************************** DOVE **********************************/
  277. int dove(double *parray,int itemcnt,double *outarray,int outcnt)
  278. {
  279. double *amp, *frq, *inarrayend = parray + itemcnt, *outarrayend = outarray + outcnt, tailstartfrq;
  280. amp = inarrayend - 1;
  281. if(!flteq(*amp,0.0)) // Input spectrum never falls to zero
  282. return(FINISHED);
  283. while(amp > parray) { // Search back from end of (orig) spectrum, until spectral vals are >0
  284. if(!flteq(*amp,0.0))
  285. break;
  286. amp -= 2;
  287. }
  288. if(amp <= parray) // (original) spectrum is everywhere zero
  289. return(FINISHED);
  290. frq = amp - 1;
  291. tailstartfrq = *frq; // Note frq at which (original) spectrum finally falls to zero
  292. frq = outarray; // Parse frq vals in output array
  293. while(frq < outarrayend) {
  294. if(*frq >= tailstartfrq) {
  295. amp = frq - 1; // Note where outfrq exceeds tailstartfrq of input, and step to amp BEFORE it
  296. break;
  297. }
  298. frq += 2;
  299. }
  300. if(frq >= outarrayend) { // Output frq never exceeds input frq: should be impossible
  301. fprintf(stderr,"DOVETAILING FAILED.\n");
  302. return(PROGRAM_ERROR);
  303. }
  304. while(amp < outarrayend) { // Search for point where output first touches zero
  305. if(flteq(*amp,0.0))
  306. break;
  307. amp += 2;
  308. }
  309. if(amp >= outarrayend) {
  310. fprintf(stderr,"NO DOVETAILING OCCURED.\n");
  311. }
  312. while(amp < outarrayend) { // Set tail to zero
  313. *amp = 0.0;
  314. amp += 2;
  315. }
  316. return(FINISHED);
  317. }
  318. /**************************** READ_VALUE_FROM_ARRAY *****************************/
  319. int read_value_from_array(double *outval,double thisfrq,double *brk,double **brkptr,int brksize,double *firstval,double *lastval,double *lastind,int *brkinit)
  320. {
  321. double *endpair, *p, val;
  322. double hival, loval, hiind, loind;
  323. if(!(*brkinit)) {
  324. *brkptr = brk;
  325. *firstval = *(brk+1);
  326. endpair = brk + ((brksize-1)*2);
  327. *lastind = *endpair;
  328. *lastval = *(endpair+1);
  329. *brkinit = 1;
  330. }
  331. p = *brkptr;
  332. if(thisfrq <= *brk) {
  333. *outval = *firstval;
  334. return(FINISHED);
  335. } else if(thisfrq >= *lastind) {
  336. *outval = *lastval;
  337. return(FINISHED);
  338. }
  339. if(thisfrq > *p) {
  340. while(*p < thisfrq)
  341. p += 2;
  342. } else {
  343. while(*p >=thisfrq)
  344. p -= 2;
  345. p += 2;
  346. }
  347. hival = *(p+1);
  348. hiind = *p;
  349. loval = *(p-1);
  350. loind = *(p-2);
  351. val = (thisfrq - loind)/(hiind - loind);
  352. val *= (hival - loval);
  353. val += loval;
  354. *outval = val;
  355. *brkptr = p;
  356. return(FINISHED);
  357. }
  358. /************************** GET_FLOAT_WITH_E_FROM_WITHIN_STRING **************************
  359. * takes a pointer TO A POINTER to a string. If it succeeds in finding
  360. * a float it returns the float value (*val), and it's new position in the
  361. * string (*str).
  362. */
  363. int get_float_with_e_from_within_string(char **str,double *val)
  364. {
  365. char *p, *valstart;
  366. int decimal_point_cnt = 0, has_digits = 0, has_e = 0, lastchar = 0;
  367. p = *str;
  368. while(isspace(*p))
  369. p++;
  370. valstart = p;
  371. switch(*p) {
  372. case('-'): break;
  373. case('.'): decimal_point_cnt=1; break;
  374. default:
  375. if(!isdigit(*p))
  376. return(FALSE);
  377. has_digits = TRUE;
  378. break;
  379. }
  380. p++;
  381. while(!isspace(*p) && *p!=NEWLINE && *p!=ENDOFSTR) {
  382. if(isdigit(*p))
  383. has_digits = TRUE;
  384. else if(*p == 'e') {
  385. if(has_e || !has_digits)
  386. return(FALSE);
  387. has_e = 1;
  388. } else if(*p == '-') {
  389. if(!has_e || (lastchar != 'e'))
  390. return(FALSE);
  391. } else if(*p == '.') {
  392. if(has_e || (++decimal_point_cnt>1))
  393. return(FALSE);
  394. } else
  395. return(FALSE);
  396. lastchar = *p;
  397. p++;
  398. }
  399. if(!has_digits || sscanf(valstart,"%lf",val)!=1)
  400. return(FALSE);
  401. *str = p;
  402. return(TRUE);
  403. }