stretcha.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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. * $Log: stretcha.c%v $
  23. * Revision 1.1 1995/12/20 17:28:54 trevor
  24. * Initial revision
  25. *
  26. */
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <math.h>
  30. #include "sfsys.h"
  31. const char* cdp_version = "7.1.0";
  32. #define PROG "STRETCHA"
  33. #define STRETCH (1)
  34. #define DUR (1)
  35. #define BEATS (2)
  36. #define TEMPO (4)
  37. #define BEATS_AND_TEMPO (6)
  38. #define MINUTE (60.0)
  39. #define ENDOFSTR ('\0')
  40. #define FLTERR 0.000002
  41. int inputt = 0, outputt = 0, result = 0;
  42. double dur, beats, tempo, odur, obeats, otempo, answer;
  43. char zag = (char)0, tthis;
  44. void usage(void), help(void), logo(void);
  45. //void read_properties(void);
  46. //void write_properties(void);
  47. void process_file(char *);
  48. void do_fraction(double);
  49. int flteq(double,double);
  50. #define finish(x) return((x))
  51. int
  52. main(int argc, char *argv[])
  53. {
  54. int n,ifd = -1;
  55. int infilesize = 0;
  56. SFPROPS props;
  57. if(sflinit("stretcha")) {
  58. sfperror("Initialisation");
  59. finish(1);
  60. }
  61. if(argc==2 && strcmp(argv[1],"--version")==0){
  62. fprintf(stdout,"%s\n",cdp_version);
  63. fflush(stdout);
  64. return 0;
  65. }
  66. if(argc==2 && !strcmp(argv[1],"-h")) {
  67. help();
  68. return 0;
  69. }
  70. if(argc < 4 || argc > 6){
  71. usage();
  72. return 1;
  73. }
  74. if(*argv[1]++!='-') {
  75. fprintf(stderr,"Parameter 1 must be a flag.\n");
  76. finish(1);
  77. }
  78. switch(*argv[1]) {
  79. case('s'): result = STRETCH; break;
  80. case('c'): result = BEATS; break;
  81. default:
  82. fprintf(stderr,"Unknown flag '-%c' as 1st parameter.\n",*argv[1]);
  83. finish(1);
  84. }
  85. n = 2;
  86. while(n<argc) {
  87. if(*argv[n]++!='-') {
  88. fprintf(stderr,"Unknown parameter '%s'.\n",--argv[n]);
  89. finish(1);
  90. }
  91. tthis = *argv[n];
  92. switch(*argv[n]++) {
  93. case('d'):
  94. if(inputt & DUR) {
  95. if(tthis==zag)
  96. fprintf(stderr,"Repetition of flag -%c\n",zag);
  97. else
  98. fprintf(stderr,"You cannot have 2 input durations (-d and -f).\n");
  99. finish(1);
  100. }
  101. zag = 'd';
  102. if((inputt & TEMPO) || (inputt & BEATS)) {
  103. fprintf(stderr,"You cannot have input duration (-%c) AND input tempo (-t) or beatcnt (-b).\n",zag);
  104. finish(1);
  105. }
  106. inputt |= DUR;
  107. if(sscanf(argv[n],"%lf",&dur)!=1) {
  108. fprintf(stderr,"Cannot read duration value with -d flag.\n");
  109. finish(1);
  110. }
  111. break;
  112. case('f'):
  113. if(inputt & DUR) {
  114. if(tthis==zag)
  115. fprintf(stderr,"Repetition of flag -%c\n",zag);
  116. else
  117. fprintf(stderr,"You cannot have 2 input durations (-d and -f).\n");
  118. finish(1);
  119. }
  120. zag = 'f';
  121. if((inputt & TEMPO) || (inputt & BEATS)) {
  122. fprintf(stderr,"You cannot have input duration (-%c) AND input tempo (-t) or beatcnt (-b).\n",zag);
  123. finish(1);
  124. }
  125. inputt |= DUR;
  126. //open_infile(argv[n]);
  127. //read_infile_size();
  128. //read_and_check_properties();
  129. ifd = sndopenEx(argv[n],0,CDP_OPEN_RDONLY);
  130. if(ifd < 0){
  131. fprintf(stderr,"unable to open sfile %s: %s\n",argv[n],sferrstr());
  132. return 1;
  133. }
  134. infilesize = sndsizeEx(ifd);
  135. if(infilesize < 0){
  136. fprintf(stderr,"error reading sfile %s: %s\n",argv[n],sferrstr());
  137. return 1;
  138. }
  139. if(snd_headread(ifd,&props) < 0){
  140. fprintf(stderr,"error reading sfile props: %s: %s\n",argv[n],sferrstr());
  141. return 1;
  142. }
  143. dur = (double)(infilesize/props.chans)/(double) props.srate;
  144. break;
  145. case('b'):
  146. if(inputt & BEATS)
  147. fprintf(stderr,"Repetition of flag -b\n");
  148. inputt |= BEATS;
  149. if(inputt & DUR) {
  150. fprintf(stderr,"You cannot have input duration (-%c) AND input beatcnt (-b).\n",zag);
  151. finish(1);
  152. }
  153. if(sscanf(argv[n],"%lf",&beats)!=1) {
  154. fprintf(stderr,"Cannot read number of beats with -b flag.\n");
  155. finish(1);
  156. }
  157. break;
  158. case('t'):
  159. if(inputt & TEMPO)
  160. fprintf(stderr,"Repetition of flag -t\n");
  161. inputt |= TEMPO;
  162. if(inputt & DUR) {
  163. fprintf(stderr,"You cannot have input duration (-%c) AND input tempo (-t).\n",zag);
  164. finish(1);
  165. }
  166. if(sscanf(argv[n],"%lf",&tempo)!=1) {
  167. fprintf(stderr,"Cannot read tempo value with -t flag.\n");
  168. finish(1);
  169. }
  170. break;
  171. case('D'):
  172. if(outputt & DUR)
  173. fprintf(stderr,"Repetition of flag -D\n");
  174. outputt |= DUR;
  175. if((outputt & TEMPO) || (outputt & BEATS)) {
  176. fprintf(stderr,"You can't have output duration (-D) AND output tempo (-T) or output beatcnt (-B).\n");
  177. finish(1);
  178. }
  179. if(sscanf(argv[n],"%lf",&odur)!=1) {
  180. fprintf(stderr,"Cannot read output duration value with -D flag.\n");
  181. finish(1);
  182. }
  183. break;
  184. case('B'):
  185. if(outputt & BEATS)
  186. fprintf(stderr,"Repetition of flag -B\n");
  187. outputt |= BEATS;
  188. if(outputt & DUR) {
  189. fprintf(stderr,"You can't have output duration (-D) AND output beatcnt (-B).\n");
  190. finish(1);
  191. }
  192. if(sscanf(argv[n],"%lf",&obeats)!=1) {
  193. fprintf(stderr,"Cannot read number of output beats with -B flag.\n");
  194. finish(1);
  195. }
  196. break;
  197. case('T'):
  198. if(outputt & TEMPO)
  199. fprintf(stderr,"Repetition of flag -T\n");
  200. outputt |= TEMPO;
  201. if(outputt & DUR) {
  202. fprintf(stderr,"You can't have output duration (-D) AND output tempo (-T).\n");
  203. finish(1);
  204. }
  205. if(sscanf(argv[n],"%lf",&otempo)!=1) {
  206. fprintf(stderr,"Cannot read output tempo value with -T flag.\n");
  207. finish(1);
  208. }
  209. break;
  210. default:
  211. fprintf(stderr,"Unknown flag '-%c'.\n",*--argv[n]);
  212. finish(1);
  213. }
  214. n++;
  215. }
  216. if(!inputt) {
  217. fprintf(stderr,"No input values given (-d,-f,-t,-b).\n");
  218. finish(1);
  219. }
  220. if(!outputt) {
  221. fprintf(stderr,"No output values given (-D,-T,-B).\n");
  222. finish(1);
  223. }
  224. if(result==BEATS && outputt!=TEMPO) {
  225. if(outputt & TEMPO)
  226. fprintf(stderr,"For a crotchet count (-c) you must have output tempo (-T) ONLY.\n");
  227. else
  228. fprintf(stderr,"For a crotchet count (-c) you must have output tempo (-T) (ONLY).\n");
  229. finish(1);
  230. }
  231. if((outputt & BEATS) && !(outputt & TEMPO)) {
  232. fprintf(stderr,"Output beatcount given (-B) WITHOUT output tempo (-T).\n");
  233. finish(1);
  234. }
  235. if((inputt & BEATS) && !(inputt & TEMPO)) {
  236. fprintf(stderr,"Input beatcount given (-b) WITHOUT input tempo (-t).\n");
  237. finish(1);
  238. }
  239. if(inputt==TEMPO && result!=STRETCH) {
  240. fprintf(stderr,"Tempo input (-t) ALONE, can only be used with stretching (-s).\n");
  241. fprintf(stderr,"Otherwise you need an input beatcount (-b).\n");
  242. finish(1);
  243. }
  244. if(inputt==TEMPO && outputt!=TEMPO) {
  245. fprintf(stderr,"Tempo input ONLY (-t), with stretching (-s), needs a tempo ONLY output (-T).\n");
  246. fprintf(stderr,"Otherwise you need an input beatcount (-b).\n");
  247. finish(1);
  248. }
  249. if(inputt!=TEMPO && result==BEATS && outputt!=TEMPO) {
  250. fprintf(stderr,"Output must be tempo ONLY (-T) with crotchet count (-b).\n");
  251. finish(1);
  252. }
  253. if(inputt!=TEMPO && result==STRETCH && outputt==TEMPO) {
  254. fprintf(stderr,"Output must be duration (-D: or -T WITH -B) if stretching (-s) a duration.\n");
  255. finish(1);
  256. }
  257. switch(result) {
  258. case(BEATS):
  259. if(inputt==BEATS_AND_TEMPO)
  260. dur = beats * MINUTE/tempo;
  261. answer = dur * otempo/MINUTE;
  262. printf("Number of beats at new tempo = %lf ",answer);
  263. do_fraction(answer);
  264. if(!flteq(answer,1.0) && answer < 1.0)
  265. printf("of a ");
  266. printf("crotchet");
  267. if(!flteq(answer,1.0) && answer > 1.0)
  268. printf("s");
  269. printf("\n");
  270. break;
  271. case(STRETCH):
  272. if(inputt==TEMPO)
  273. answer = tempo/otempo;
  274. else {
  275. if(inputt == BEATS_AND_TEMPO)
  276. dur = beats * MINUTE/tempo;
  277. if(outputt== BEATS_AND_TEMPO)
  278. odur = obeats * MINUTE/otempo;
  279. answer = odur/dur;
  280. }
  281. printf("Stretchfactor = %lf\n",answer);
  282. break;
  283. }
  284. finish(0);
  285. }
  286. /*************************************** USAGE ***********************************/
  287. void usage(void)
  288. {
  289. logo();
  290. fprintf(stderr, "USAGES:\n");
  291. fprintf(stderr, "stretcha -c -ddur|-fsndfile|(-bbeats -ttempo) -Touttempo\n");
  292. fprintf(stderr, "stretcha -s -ddur|-fsndfile|(-bbeats -ttempo) -Doutdur|(-Boutbeats -Touttempo)\n");
  293. fprintf(stderr, "stretcha -s -tintempo -Touttempo\n\n");
  294. fprintf(stderr, "-----------for more information, type 'stretcha -h' -------------\n");
  295. }
  296. /*************************************** HELP ***********************************/
  297. void help(void)
  298. {
  299. fprintf(stderr, "stretcha -s takes...\n");
  300. fprintf(stderr, "\t An INPUT DURATION and an OUTPUT DURATION.\n");
  301. fprintf(stderr, "\tOR: An INPUT TEMPO and an OUTPUT TEMPO.\n");
  302. fprintf(stderr, "It calculates stretch required to timewarp a sound from one frame to other.\n\n");
  303. fprintf(stderr, "stretcha -c takes...\n");
  304. fprintf(stderr, "\t AN INPUT DURATION and AN OUTPUT TEMPO.\n");
  305. fprintf(stderr, "It calculates number of crotchet beats sound will occupy at new tempo.\n\n");
  306. fprintf(stderr, "INPUT DURATION is input in secs, or as a sndfile (the program finds its dur),\n");
  307. fprintf(stderr, " or as a crotchet count (possibly fractional) WITH a tempo.\n");
  308. fprintf(stderr, "OUTPUT DURATION can be secs, or can be a crotchet count WITH a tempo.\n\n");
  309. }
  310. /*********************************** DO_FRACTION ******************************/
  311. void do_fraction(double val)
  312. {
  313. int n, m, k = 0;
  314. double d, test;
  315. for(n=2;n<17;n++) {
  316. d = 1.0/(double)n;
  317. if((test = fmod(val,d))< FLTERR || d - test < FLTERR) {
  318. m = (int)(val/d); /* truncate */
  319. if(!flteq((double)m * d,val))
  320. m++;
  321. if(!flteq((double)m * d,val)) {
  322. m-=2;
  323. if(!flteq((double)m * d,val)) {
  324. fprintf(stderr,"Problem in fractions\n");
  325. return;
  326. }
  327. }
  328. if(m > n) {
  329. k = m/n; /* truncate */
  330. m -= k * n;
  331. }
  332. printf("(");
  333. if(k)
  334. printf("%d & ",k);
  335. printf("%d/%d) ",m,n);
  336. break;
  337. }
  338. }
  339. }
  340. /*********************************** FLTEQ ******************************/
  341. int flteq(double a,double b)
  342. {
  343. double hibound = a + FLTERR;
  344. double lobound = a - FLTERR;
  345. if(b > hibound || b < lobound)
  346. return(0);
  347. return(1);
  348. }
  349. /******************************** LOGO() **********************************/
  350. void logo(void)
  351. { printf("\t ***************************************************\n");
  352. printf("\t * COMPOSERS DESKTOP PROJECT *\n");
  353. printf("\t %s $Revision: 6.0.0 $\n",PROG);
  354. printf("\t * *\n");
  355. printf("\t * Calculate required time-stretches. *\n");
  356. printf("\t * *\n");
  357. printf("\t * by TREVOR WISHART *\n");
  358. printf("\t ***************************************************\n\n");
  359. }