maxsamp2.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * Copyright (c) 1983-2023 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. MAXSAMP2.C
  23. usage maxsamp2 infile
  24. Finds the maximum sample of a file and writes it to the header.
  25. Based on maxsamp in CDPARSE
  26. **************************************************************************/
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <osbind.h>
  31. #include <math.h>
  32. #include <float.h>
  33. #include <float.h>
  34. #include <sfsys.h>
  35. #include <cdplib.h>
  36. /*static void usage(void);*/
  37. static void report(void);
  38. static int tidy_up(int);
  39. static void min_sec(int,int,int*,double*);
  40. static void find_fmax(float*,int,int);
  41. static int try_header(int);
  42. static int open_in(char*,int);
  43. static int get_big_buf(void);
  44. static int get_max_samp(int,int);
  45. static int smpflteq(double f1,double f2);
  46. static void force_new_header(void);
  47. float *bigfbuf; /* buffer used to read samples from soundfile */
  48. size_t buflen; /* buffer length in samps (eventually) */
  49. int ifd; /* input soundfile descriptor */
  50. int srate = 44100; /* sampling rate of input */
  51. int channels = 2; /* number of channels of input */
  52. double maxpdamp = DBL_MIN; /* value of maximum negative sample */
  53. double maxndamp = DBL_MAX; /* value of maximum positive sample */
  54. float maxpfamp; /* float value of maximum positive sample */
  55. float maxnfamp; /* float value of maximum negative sample */
  56. double maxdamp = 0.0; /* value of maximum sample */
  57. int maxloc = 0; /* location of maximum sample */
  58. int repeats = 1; /* counts how many times the maximum repeats */
  59. int pos_repeats = 0;
  60. int neg_repeats = 0;
  61. int in_header = 0;
  62. unsigned int maxnloc, maxploc;
  63. unsigned int *maxcnloc, *maxcploc;
  64. double *maxcpdamp, *maxcndamp;
  65. int *posreps, *negreps;
  66. const char* cdp_version = "7.1.0";
  67. int open_in(char *name,int force_read) /* opens input soundfile and gets header */
  68. {
  69. int is_sound = 0;
  70. SFPROPS props = {0};
  71. int open_type;
  72. if(force_read)
  73. open_type = CDP_OPEN_RDWR;
  74. else
  75. open_type = CDP_OPEN_RDONLY;
  76. if( (ifd = sndopenEx(name,0,open_type)) < 0 ) {
  77. fprintf(stdout,"INFO: Cannot open file: %s\n\t",name);
  78. fflush(stdout);
  79. return(-1);
  80. }
  81. if(!snd_headread(ifd,&props)) {
  82. fprintf(stdout,"Failure to read sample size\n");
  83. fflush(stdout);
  84. return(-1);
  85. }
  86. if(props.type != 0) {
  87. fprintf(stdout,"Not a soundfile\n");
  88. fflush(stdout);
  89. return(-1);
  90. }
  91. srate = props.srate;
  92. channels = props.chans;
  93. return(is_sound);
  94. }
  95. int get_big_buf(void) /* allocates memory for the biggest possible buffer */
  96. {
  97. size_t i;
  98. buflen = (size_t) Malloc(-1) - sizeof(float);
  99. /* if less than one sector available */
  100. if( buflen < SECSIZE || ((bigfbuf=(float*)Malloc(buflen+sizeof(float))) == NULL)) {
  101. fprintf(stdout,"ERROR: Failed to allocate float buffer.\n");
  102. fflush(stdout);
  103. return 0;
  104. }
  105. i = ((size_t)bigfbuf+sizeof(float)-1)/sizeof(float)*sizeof(float); /* align bigbuf to word boundary */
  106. bigfbuf = (float*)i;
  107. buflen /= sizeof(float);
  108. buflen = (buflen/channels) * channels; /* align buflen to channel boundaries */
  109. if(buflen <= 0) {
  110. fprintf(stdout,"ERROR: Failed to allocate float buffer.\n");
  111. fflush(stdout);
  112. return 0;
  113. }
  114. return 1;
  115. }
  116. int get_max_samp(int ifd,int force_read)
  117. {
  118. int got;
  119. int totalsamps = 0;
  120. int mins;
  121. double sec;
  122. // int total_got = 0;
  123. int j;
  124. switch(force_read) {
  125. case(0):
  126. if(try_header(ifd) >= 0) // No forcing: "try_header" succeeds. Maxsamp can be >0 or 0
  127. return(0);
  128. break;
  129. case(2):
  130. if(try_header(ifd) > 0) // "try_header" succeeds. Maxsamp can be >0 but NOT 0
  131. return(0); // if maxsamp is 0, searching for maxsamp is forced
  132. force_read = 1;
  133. break;
  134. /* else if info is not in header */
  135. }
  136. /* read and find maximum */
  137. while( (got = fgetfbufEx(bigfbuf,(int) buflen,ifd,0)) > 0 ) {
  138. // total_got += got;
  139. find_fmax(bigfbuf,got,totalsamps);
  140. totalsamps += got;
  141. }
  142. if( got < 0 ) {
  143. min_sec((int)(totalsamps/channels),srate,&mins,&sec);
  144. fprintf(stdout,"ERROR: An error has occured. The current Location is:\t %d min %6.3lf sec\n",mins,sec);
  145. fprintf(stdout,"ERROR: The maximum sample found so far is: %lf\n",maxdamp);
  146. fflush(stdout);
  147. return(-1);
  148. }
  149. maxpdamp = maxcpdamp[0];
  150. maxndamp = maxcndamp[0];
  151. maxploc = maxcploc[0];
  152. maxnloc = maxcnloc[0];
  153. pos_repeats = posreps[0];
  154. neg_repeats = negreps[0];
  155. for(j=1;j < channels; j++) {
  156. if(maxcpdamp[j] > maxpdamp) {
  157. maxpdamp = maxcpdamp[j];
  158. maxploc = maxcploc[j];
  159. pos_repeats = posreps[j];
  160. } else if (maxcpdamp[j] < maxpdamp)
  161. ;
  162. else if(maxcploc[j] < maxploc) // equal +ve vals
  163. maxploc = maxcploc[j];
  164. if(maxcndamp[j] < maxndamp) {
  165. maxndamp = maxcndamp[j];
  166. maxnloc = maxcnloc[j];
  167. neg_repeats = negreps[j];
  168. } else if (maxcndamp[j] > maxndamp)
  169. ;
  170. else if(maxcnloc[j] < maxnloc) // equal -ve vals
  171. maxnloc = maxcnloc[j];
  172. }
  173. maxpfamp = (float)maxpdamp;
  174. maxnfamp = (float)maxndamp;
  175. if(maxpdamp > -maxndamp)
  176. maxdamp = maxpdamp;
  177. else
  178. maxdamp = fabs(maxndamp);
  179. return(0);
  180. }
  181. void
  182. report(void)
  183. {
  184. int mins, maxchan = 0;
  185. double sec;
  186. if (!in_header && !pos_repeats && !neg_repeats) {
  187. fprintf(stdout,"INFO: All samples are zero.\n");
  188. fflush(stdout);
  189. return;
  190. }
  191. if(in_header) {
  192. fprintf(stdout,"KEEP: %lf %d %d\n",maxdamp,maxloc,-1);
  193. } else {
  194. if(maxpdamp > -maxndamp) {
  195. maxloc = maxploc;
  196. repeats = pos_repeats;
  197. } else if(maxpdamp < -maxndamp) {
  198. maxloc = maxnloc;
  199. repeats = neg_repeats;
  200. } else {
  201. maxloc = min(maxploc,maxnloc);
  202. repeats = neg_repeats + pos_repeats;
  203. }
  204. maxchan = (maxloc % channels)+1;
  205. maxloc /= channels;
  206. fprintf(stdout,"KEEP: %lf %d %d\n",maxdamp,maxloc,repeats);
  207. if(pos_repeats)
  208. fprintf(stdout,"INFO: Maximum positive sample: %f\n",maxpfamp);
  209. if(neg_repeats)
  210. fprintf(stdout,"INFO: Maximum negative sample: %f\n",maxnfamp);
  211. }
  212. fprintf(stdout,"INFO: Maximum ABSOLUTE sample: %lf\n",maxdamp);
  213. min_sec(maxloc,srate,&mins,&sec);
  214. if(maxchan > 0)
  215. fprintf(stdout,"INFO: Location of maximum sample: %d min %7.4lf sec: chan %d\n",mins,sec,maxchan);
  216. else
  217. fprintf(stdout,"INFO: Location of maximum sample: %d min %7.4lf sec\n",mins,sec);
  218. if(!in_header) {
  219. fprintf(stdout,"INFO: Number of times found: %-d\n",repeats);
  220. }
  221. fprintf(stdout,"INFO: Maximum possible dB gain: %-7.3lf\n",20.0*log10(1.0/maxdamp));
  222. fprintf(stdout,"INFO: Maximum possible gain factor: %-9.3lf\n",1.0/maxdamp);
  223. fflush(stdout);
  224. }
  225. int tidy_up(int where)
  226. {
  227. switch(where)
  228. {
  229. case 0:
  230. Mfree(bigfbuf);
  231. case 1:
  232. sndcloseEx(ifd);
  233. case 2:
  234. // sffinish();
  235. default:
  236. break;
  237. }
  238. return(1);
  239. }
  240. int main(int argc,char *argv[])
  241. {
  242. int force_read = 0, j;
  243. /*TICK */ // unsigned int time;
  244. int is_sound;
  245. /* get current time */
  246. // time = hz200();
  247. if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
  248. fprintf(stdout,"%s\n",cdp_version);
  249. fflush(stdout);
  250. return 0;
  251. }
  252. if(argc == 3) {
  253. if(sscanf(argv[2],"%d",&force_read) != 1) {
  254. fprintf(stdout,"ERROR: bad 2nd parameter.\n");
  255. fflush(stdout);
  256. return tidy_up(3);
  257. }
  258. if(force_read < 1 || force_read > 2) {
  259. fprintf(stdout,"ERROR: bad 2nd parameter.\n");
  260. fflush(stdout);
  261. return tidy_up(3);
  262. }
  263. argc--;
  264. }
  265. if(argc !=2) {
  266. fprintf(stdout,"ERROR: wrong number of arguments.\n");
  267. fflush(stdout);
  268. return tidy_up(3);
  269. }
  270. /* initialise SFSYS */
  271. if( sflinit("maxsamp2") < 0 )
  272. {
  273. fprintf(stdout,"ERROR: Cannot initialise soundfile system.\n");
  274. fflush(stdout);
  275. return tidy_up(3);
  276. }
  277. /* open input file */
  278. if((is_sound = open_in(argv[1],force_read)) < 0)
  279. return tidy_up(2);
  280. /* get biggest buffer */
  281. if(get_big_buf() == 0)
  282. return tidy_up(1);
  283. if((maxcploc = (unsigned int *)malloc(channels * sizeof(unsigned int))) == NULL)
  284. return tidy_up(0);
  285. if((maxcnloc = (unsigned int *)malloc(channels * sizeof(unsigned int))) == NULL)
  286. return tidy_up(0);
  287. if((maxcpdamp = (double *)malloc(channels * sizeof(double))) == NULL)
  288. return tidy_up(0);
  289. if((maxcndamp = (double *)malloc(channels * sizeof(double))) == NULL)
  290. return tidy_up(0);
  291. if((posreps = (int *)malloc(channels * sizeof(int))) == NULL)
  292. return tidy_up(0);
  293. if((negreps = (int *)malloc(channels * sizeof(int))) == NULL)
  294. return tidy_up(0);
  295. for(j=0;j<channels;j++) {
  296. maxcploc[j] = 0;
  297. maxcnloc[j] = 0;
  298. maxcpdamp[j] = DBL_MIN;
  299. maxcndamp[j] = DBL_MAX;
  300. posreps[j] = 0;
  301. negreps[j] = 0;
  302. }
  303. /* max soundfiles */
  304. get_max_samp(ifd,force_read);
  305. /* send report */
  306. if(force_read)
  307. force_new_header();
  308. report();
  309. /* tidy up */
  310. return tidy_up(0);
  311. }
  312. /* converts samples into minutes and seconds */
  313. void min_sec(int value,int srate,int *mins,double *secs)
  314. {
  315. *secs = (double)value/srate;
  316. *mins = (int)floor(*secs/60);
  317. *secs -= *mins*60;
  318. }
  319. /**************************** SMPFLTEQ *******************************/
  320. #define SMP_FLTERR 0.0000005
  321. int smpflteq(double f1,double f2)
  322. {
  323. double upperbnd, lowerbnd;
  324. upperbnd = f2 + SMP_FLTERR;
  325. lowerbnd = f2 - SMP_FLTERR;
  326. if((f1>upperbnd) || (f1<lowerbnd))
  327. return(0);
  328. return(1);
  329. }
  330. /**************************** TRY_HEADER ****************************
  331. *
  332. * checks if maxsamp information is in header
  333. */
  334. int try_header(int ifd)
  335. {
  336. int j;
  337. CHPEAK *peakdata;
  338. int peaktime;
  339. maxloc = sndsizeEx(ifd);
  340. if((peakdata = (CHPEAK *)malloc(channels * sizeof(CHPEAK)))==NULL) {
  341. return -1;
  342. }
  343. if(sndreadpeaks(ifd,channels,peakdata,&peaktime) < 0)
  344. return -1;
  345. for(j=0;j<channels;j++) {
  346. if(peakdata[j].value > maxdamp) {
  347. maxdamp = peakdata[j].value;
  348. maxloc = peakdata[j].position;
  349. } else if(!(peakdata[j].value < maxdamp)) { /* i.e. equal values */
  350. maxloc = min(peakdata[j].position,(unsigned int)maxloc);
  351. }
  352. }
  353. if(maxdamp == 0.0) {
  354. maxloc = 0;
  355. return 0;
  356. }
  357. in_header = 1;
  358. return 1;
  359. }
  360. void find_fmax(float *buffer,int samps,int totalsamps)
  361. {
  362. int i, j;
  363. for(j=0;j < channels; j++) {
  364. maxpdamp = 0.0;
  365. maxndamp = 0.0;
  366. for( i=j ; i<samps ; i+=channels ) {
  367. if(maxcpdamp[j] > 0.0 && smpflteq(buffer[i],maxcpdamp[j]))
  368. posreps[j]++;
  369. else if(maxcndamp[j] < 0.0 && smpflteq(buffer[i],maxcndamp[j]))
  370. negreps[j]++;
  371. else if( buffer[i] > maxcpdamp[j]) {
  372. maxcpdamp[j] = buffer[i];
  373. posreps[j] = 1;
  374. maxcploc[j] = totalsamps + i;
  375. } else if ( buffer[i] < maxcndamp[j] ) {
  376. maxcndamp[j] = buffer[i];
  377. negreps[j] = 1;
  378. maxcnloc[j] = totalsamps + i;
  379. }
  380. }
  381. }
  382. }
  383. void force_new_header(void) {
  384. int j;
  385. unsigned int maxp;
  386. double maxv;
  387. CHPEAK *peakdata;
  388. if((peakdata = (CHPEAK *)malloc(channels * sizeof(CHPEAK)))==NULL) {
  389. return;
  390. }
  391. for(j=0;j<channels;j++) {
  392. if(-maxcpdamp[j] < maxcndamp[j]) {
  393. maxv = maxcpdamp[j];
  394. maxp = maxcploc[j];
  395. } else if(-maxcpdamp[j] > maxcndamp[j]) {
  396. maxv = maxcndamp[j];
  397. maxp = maxcnloc[j];
  398. } else { // equal
  399. if(maxcnloc[j] < maxcploc[j]) {
  400. maxv = maxcndamp[j];
  401. maxp = maxcnloc[j];
  402. } else {
  403. maxv = maxcpdamp[j];
  404. maxp = maxcploc[j];
  405. }
  406. }
  407. peakdata[j].value = (float)maxv;
  408. peakdata[j].position = maxp;
  409. }
  410. if(sndputpeaks(ifd,channels,peakdata)<0) {
  411. fprintf(stderr,"NO HEADER WRITE: %s\n",sferrstr());
  412. }
  413. }