stretch.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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 <structures.h>
  24. #include <tkglobals.h>
  25. #include <pnames.h>
  26. #include <globcon.h>
  27. #include <modeno.h>
  28. #include <arrays.h>
  29. #include <stretch.h>
  30. #include <cdpmain.h>
  31. #include <formants.h>
  32. #include <speccon.h>
  33. #include <sfsys.h>
  34. #include <string.h>
  35. #include <stretch.h>
  36. //#ifdef unix
  37. #define round(x) lround((x))
  38. //#endif
  39. static int do_constant_timestretch(int *thatwindow,dataptr dz);
  40. static int do_timevariable_timestretch(int *thatwindow,dataptr dz);
  41. static int do_timestretching(int *thatwindow,int count,dataptr dz);
  42. static int do_timevariable_count(int *outcnt,dataptr dz);
  43. static int divide_time_into_equal_increments(int *thatwindow,int startwindow,
  44. double dur,int count,dataptr dz);
  45. static int get_both_vals_from_brktable(double *thistime,double *thisstretch,int brktab_no,dataptr dz);
  46. static int timestretch_this_segment(int *thatwindow,int startwindow,
  47. double thiswdur,double nextwdur,int totaldur,dataptr dz);
  48. static int advance_along_input_windows(int wdw_to_advance,int atend,dataptr dz);
  49. static double calculate_number_of_output_windows(double startwdur,double endwdur,int totaldur);
  50. static int calc_position_output_wdws_relative_to_input_wdws_for_decreasing_stretch
  51. (int *thatwindow,int startwindow,int count,int totaldur,
  52. double param0,double param1,double param2,dataptr dz);
  53. static int calc_position_output_wdws_relative_to_input_wdws_for_increasing_stretch
  54. (int *thatwindow,int startwindow,int count,
  55. double param0,double param1,double param2,dataptr dz);
  56. static double calculate_position(int x,double param0,double param1,double param2);
  57. static int retrograde_sequence_of_time_intervals(int endtime,int count,double *startptr,dataptr dz);
  58. static int stretch_spectrum(double shift,dataptr dz);
  59. /********************************** SPECTSTRETCH **********************************
  60. *
  61. * Timestretch spectrum.
  62. */
  63. int spectstretch(dataptr dz)
  64. {
  65. int exit_status;
  66. int thatwindow, outcnt = 0;
  67. int samps_read;
  68. switch(dz->mode) {
  69. case(TSTR_NORMAL):
  70. if((samps_read = fgetfbufEx(dz->flbufptr[0], dz->big_fsize,dz->ifd[0],0)) < 0) {
  71. sprintf(errstr,"No data found in input soundfile.\n");
  72. return(DATA_ERROR);
  73. }
  74. if(sloom)
  75. dz->total_samps_read = samps_read;
  76. dz->flbufptr[3] = dz->flbufptr[0];
  77. dz->flbufptr[4] = dz->flbufptr[0] + dz->wanted;
  78. thatwindow = 0;
  79. if(dz->brksize[TSTR_STRETCH]==0)
  80. exit_status = do_constant_timestretch(&thatwindow,dz);
  81. else
  82. exit_status = do_timevariable_timestretch(&thatwindow,dz);
  83. if(exit_status<0)
  84. return(exit_status);
  85. if((exit_status = do_timestretching(&thatwindow,dz->ptr[TSTR_PBUF] - dz->parray[TSTR_PBUF],dz))<0)
  86. return(exit_status);
  87. if(dz->flbufptr[5] - dz->flbufptr[1] > 0)
  88. return write_samps(dz->flbufptr[1],dz->flbufptr[5] - dz->flbufptr[1],dz);
  89. return FINISHED;
  90. case(TSTR_LENGTH):
  91. if(dz->brksize[TSTR_STRETCH]==0)
  92. outcnt = round(fabs((double)dz->wlength * dz->param[TSTR_STRETCH]));
  93. else if((exit_status = do_timevariable_count(&outcnt,dz))<0)
  94. return(exit_status);
  95. fprintf(stdout,"INFO: Length of output file will be %.3lf secs.\n",outcnt * dz->frametime);
  96. fflush(stdout);
  97. break;
  98. default:
  99. sprintf(errstr,"Unknown mode in specstretch()\n");
  100. return(PROGRAM_ERROR);
  101. }
  102. return(FINISHED);
  103. }
  104. /******************************* DO_CONSTANT_TIMESTRETCH ****************************
  105. *
  106. * Set up array of indices for reading source window values into new
  107. * windows.
  108. *
  109. * (0) Initialise position-buffer pointer and start window.
  110. * (1) Get first breakpoint pair from brkpoint table.
  111. * (2) Calculate initial time as whole number of WINDOWS.
  112. * (3) If time is stretched, output window is SHRUNK relative to input
  113. * window. Hence val = 1/stretch.
  114. * (4) Proceed in a loop of all input breakpoint values.
  115. * (5) Returns if premature end of file encountered.
  116. */
  117. int do_constant_timestretch(int *thatwindow,dataptr dz)
  118. {
  119. double thiswdur, dcount, dur;
  120. int count;
  121. int startwindow = 0;
  122. dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];
  123. thiswdur = 1.0/dz->param[TSTR_STRETCH]; /* 3 */
  124. dcount = (double)dz->wlength/thiswdur;
  125. count = round(fabs(dcount));
  126. dur = (double)dz->wlength/(double)count;
  127. return divide_time_into_equal_increments(thatwindow,startwindow,dur,count,dz);
  128. }
  129. /******************************* DO_TIMEVARIABLE_TIMESTRETCH ****************************
  130. *
  131. * Set up array of indices for reading source window values into new
  132. * windows.
  133. *
  134. * (0) Initialise position-buffer pointer and start window.
  135. * (1) Get first breakpoint pair from brkpoint table.
  136. * (2) Calculate initial time as whole number of WINDOWS.
  137. * (3) If time is stretched, output window is SHRUNK relative to input
  138. * window. Hence val = 1/stretch.
  139. * (4) Proceed in a loop of all input breakpoint values.
  140. * (5) Returns if brkpnt times ran off end of source soundfile.
  141. */
  142. int do_timevariable_timestretch(int *thatwindow,dataptr dz)
  143. {
  144. int exit_status;
  145. int time0, time1, time2, totaldur;
  146. double stretch0, stretch1, thiswdur, nextwdur, valdiff, dtime0, dtime1;
  147. int atend = FALSE;
  148. int startwindow = 0; /* 0 */
  149. int timestretch_called = FALSE;
  150. dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];
  151. if((exit_status = get_both_vals_from_brktable(&dtime0,&stretch0,TSTR_STRETCH,dz))<0) /* 1 */
  152. return(exit_status);
  153. if(exit_status == FINISHED) {
  154. sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_timestretch()\n");
  155. return(PROGRAM_ERROR);
  156. }
  157. time0 = round(dtime0/dz->frametime); /* 2 */
  158. thiswdur = 1.0/stretch0; /* 3 */
  159. while((exit_status = get_both_vals_from_brktable(&dtime1,&stretch1,TSTR_STRETCH,dz))==CONTINUE) {/* 4 */
  160. nextwdur = 1.0/stretch1;
  161. if((time1 = round(dtime1/dz->frametime)) > dz->wlength) {
  162. time2 = time1; /* 5 */
  163. time1 = round(dz->param[TSTR_TOTIME]/dz->frametime);
  164. valdiff = nextwdur - thiswdur;
  165. valdiff *= (double)(time1 - time0)/(double)(time2 - time0);
  166. nextwdur = thiswdur + valdiff;
  167. atend = TRUE;
  168. }
  169. totaldur = time1 - time0;
  170. timestretch_called = TRUE;
  171. if((exit_status = timestretch_this_segment(thatwindow,startwindow,thiswdur,nextwdur,totaldur,dz))<0)
  172. return(exit_status);
  173. startwindow += totaldur;
  174. thiswdur = nextwdur;
  175. time0 = time1;
  176. if(atend)
  177. break;
  178. }
  179. if(timestretch_called == FALSE) {
  180. sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_timestretch()\n");
  181. return(PROGRAM_ERROR);
  182. }
  183. return(FINISHED);
  184. }
  185. /*************************** DO_TIMESTRETCHING ********************************
  186. *
  187. * Read/interpolate source analysis windows.
  188. *
  189. * (1) initialise the position-buffer pointer. NB we don't use pbufptr as
  190. * this is (?) still marking the current position in the output buffer.
  191. * (2) For each entry in the position-array.
  192. * (3) get the absolute position.
  193. * (4) The window to intepolate FROM is this truncated
  194. * e.g. position 3.2 translates to window 3.
  195. * (5) Is this is a move on from the current window position? How far?
  196. * (6) If we're in the final window, set the 'atend' flag.
  197. * (7) If we need to move on, call advance-windows and set up a new PAIR of
  198. * input windows.
  199. * (8) Get Interpolation time-fraction.
  200. * (9) Get output values by interpolation between input values.
  201. * (10) Write a complete out-windowbuf to output file.
  202. * (11) Give on-screen user information.
  203. */
  204. int do_timestretching(int *thatwindow,int count,dataptr dz)
  205. {
  206. int exit_status;
  207. double amp0, amp1, phas0, phas1;
  208. int vc;
  209. int n, thiswindow, step;
  210. int atend = FALSE;
  211. double here, frac;
  212. double *p = dz->parray[TSTR_PBUF]; /* 1 */
  213. for(n=0;n<count;n++) { /* 2 */
  214. here = *p++; /* 3 */
  215. thiswindow = (int)here; /* TRUNCATE */ /* 4 */
  216. step = thiswindow - *thatwindow; /* 5 */
  217. if(thiswindow == dz->wlength-1) /* 6 */
  218. atend = TRUE;
  219. if(step) {
  220. if((exit_status = advance_along_input_windows(step,atend,dz))<0) /* 7 */
  221. return(exit_status);
  222. }
  223. frac = here - (double)thiswindow; /* 8 */
  224. for(vc = 0; vc < dz->wanted; vc += 2) {
  225. amp0 = dz->flbufptr[3][AMPP]; /* 9 */
  226. phas0 = dz->flbufptr[3][FREQ];
  227. amp1 = dz->flbufptr[4][AMPP];
  228. phas1 = dz->flbufptr[4][FREQ];
  229. dz->flbufptr[5][AMPP] = (float)(amp0 + ((amp1 - amp0) * frac));
  230. dz->flbufptr[5][FREQ] = (float)(phas0 + ((phas1 - phas0) * frac));
  231. }
  232. if((dz->flbufptr[5] += dz->wanted) >= dz->flbufptr[2]) {
  233. if((exit_status = write_exact_samps(dz->flbufptr[1],dz->big_fsize,dz))<0)
  234. return(exit_status);
  235. dz->flbufptr[5] = dz->flbufptr[1];
  236. }
  237. *thatwindow = thiswindow;
  238. }
  239. return(FINISHED);
  240. }
  241. /******************************* DO_TIMEVARIABLE_COUNT *****************************/
  242. int do_timevariable_count(int *outcnt,dataptr dz)
  243. {
  244. int exit_status;
  245. int time0, time1, time2, totaldur;
  246. double stretch0, stretch1, thiswdur, nextwdur, valdiff, dtime0, dtime1;
  247. int atend = FALSE;
  248. int timestretch_called = FALSE;
  249. if((exit_status = get_both_vals_from_brktable(&dtime0,&stretch0,TSTR_STRETCH,dz))==FINISHED) {
  250. sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_count()\n");
  251. return(PROGRAM_ERROR);
  252. }
  253. time0 = round(dtime0/dz->frametime); /* 2 */
  254. thiswdur = 1.0/stretch0; /* 3 */
  255. while((exit_status = get_both_vals_from_brktable(&dtime1,&stretch1,TSTR_STRETCH,dz))==CONTINUE) {/* 4 */
  256. nextwdur = 1.0/stretch1;
  257. if((time1 = round(dtime1/dz->frametime)) > dz->wlength) {
  258. time2 = time1; /* 5 */
  259. time1 = round(dz->param[TSTR_TOTIME]/dz->frametime);
  260. valdiff = nextwdur - thiswdur;
  261. valdiff *= (double)(time1 - time0)/(double)(time2 - time0);
  262. nextwdur = thiswdur + valdiff;
  263. atend = TRUE;
  264. }
  265. totaldur = time1 - time0;
  266. timestretch_called = TRUE;
  267. *outcnt += round(fabs(calculate_number_of_output_windows(thiswdur,nextwdur,totaldur)));
  268. thiswdur = nextwdur;
  269. time0 = time1;
  270. if(atend)
  271. break;
  272. }
  273. if(timestretch_called == FALSE) {
  274. sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_count()\n");
  275. return(PROGRAM_ERROR);
  276. }
  277. return(FINISHED);
  278. }
  279. /**************************** DIVIDE_TIME_INTO_EQUAL_INCREMENTS *****************************
  280. *
  281. * all time intervals are equal. Divide up total time thus.
  282. */
  283. int divide_time_into_equal_increments(int *thatwindow,int startwindow,double dur,int count,dataptr dz)
  284. {
  285. int exit_status;
  286. int n, remnant;
  287. int end = dz->ptr[TSTR_PEND] - dz->ptr[TSTR_PBUF];
  288. int start = 0;
  289. while(count >= end) {
  290. for(n = start; n < end; n++)
  291. *(dz->ptr[TSTR_PBUF])++ = (dur * (double)n) + (double)startwindow;
  292. if((exit_status = do_timestretching(thatwindow,dz->iparam[TSTR_ARRAYSIZE],dz))<0)
  293. return(exit_status);
  294. dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];
  295. start = end;
  296. end += dz->iparam[TSTR_ARRAYSIZE];
  297. }
  298. if((remnant = count - start)>0) {
  299. for(n=start;n<count;n++)
  300. *(dz->ptr[TSTR_PBUF])++ = (dur * (double)n) + (double)startwindow;
  301. }
  302. return(FINISHED);
  303. }
  304. /**************************** GET_BOTH_VALS_FROM_BRKTABLE ****************************/
  305. int get_both_vals_from_brktable(double *thistime,double *thisstretch,int brktab_no,dataptr dz)
  306. {
  307. double *brkend = dz->brk[brktab_no] + (dz->brksize[brktab_no] * 2);
  308. if(dz->brkptr[brktab_no]>=brkend)
  309. return(FINISHED);
  310. *thistime = *(dz->brkptr[brktab_no])++;
  311. if(dz->brkptr[brktab_no]>=brkend) {
  312. sprintf(errstr,"Anomaly in get_both_vals_from_brktable().\n");
  313. return(PROGRAM_ERROR);
  314. }
  315. *thisstretch = *(dz->brkptr[brktab_no])++;
  316. return(CONTINUE);
  317. }
  318. /************************** TIMESTRETCH_THIS_SEGMENT *****************************
  319. *
  320. * Takes a group of input windows, counts number of output windows
  321. * corresponding to this buffer, and sets up, in pbuff, array(s) of values
  322. * which are the positions in the input array corresponding to the output
  323. * array positions.
  324. * (1) If there is (almost) no change in duration of segments, calculates
  325. * times on simple additive basis.
  326. * (2) Otherwise, uses exponential formula.
  327. * (3) If NOT passed a negative number (i.e. flagged), the sequence of time
  328. * intervals is reversed.
  329. */
  330. int timestretch_this_segment(int *thatwindow,int startwindow,double thiswdur,double nextwdur,int totaldur,dataptr dz)
  331. {
  332. int stretch_decreasing = TRUE;
  333. int count;
  334. double dur, dcount = calculate_number_of_output_windows(thiswdur,nextwdur,totaldur);
  335. double param0, param1, param2;
  336. if(dcount < 0.0)
  337. stretch_decreasing = FALSE;
  338. count = round(fabs(dcount));
  339. if(fabs(nextwdur - thiswdur)<=FLTERR) { /* 1 */
  340. dur = (double)totaldur/(double)count;
  341. return divide_time_into_equal_increments(thatwindow,startwindow,dur,count,dz);
  342. }
  343. param0 = nextwdur - thiswdur; /* 2 */
  344. param1 = param0/(double)totaldur;
  345. param2 = thiswdur * (double)totaldur;
  346. if(stretch_decreasing==TRUE) /* 3 */
  347. return calc_position_output_wdws_relative_to_input_wdws_for_decreasing_stretch
  348. (thatwindow,startwindow,count,totaldur,param0,param1,param2,dz);
  349. else
  350. return calc_position_output_wdws_relative_to_input_wdws_for_increasing_stretch
  351. (thatwindow,startwindow,count,param0,param1,param2,dz);
  352. }
  353. /*************************** ADVANCE_ALONG_INPUT_WINDOWS ****************************
  354. *
  355. * Advance window frame in input.
  356. * (1) If got to end of data... Advanve ONE LESS than the distance
  357. * (wdw_to_advance) from last window-pair.
  358. * (2) Else, advance by cnt windows.
  359. * (3) If at end of buffer, copy THIS window to start of whole buffer,
  360. * (4) And read more data in AFTER that (dz->wanted samps from start).
  361. * (6) If this is the last window in the source file, there is no other
  362. * window to interpolate to, so set last window to same as this.
  363. */
  364. int advance_along_input_windows(int wdw_to_advance,int atend,dataptr dz)
  365. {
  366. int n, count;
  367. int samps_read;
  368. if(atend) /* 1 */
  369. count = wdw_to_advance-1;
  370. else /* 2 */
  371. count = wdw_to_advance;
  372. for(n=0;n<count;n++) {
  373. dz->flbufptr[3] = dz->flbufptr[4]; /* ADVANCE LASTWINDOW TO THISWINDOW */
  374. if((dz->flbufptr[4] += dz->wanted) > dz->flbufptr[1]) { /* ADVANCE THISWINDOW TO NEXT */
  375. memmove((char *)dz->bigfbuf,(char *)dz->flbufptr[3],dz->wanted * sizeof(float));
  376. dz->flbufptr[3] = dz->bigfbuf; /* 3 */
  377. dz->flbufptr[4] = dz->flbufptr[0]; /* 4 */
  378. if((samps_read = fgetfbufEx(dz->flbufptr[4],dz->big_fsize,dz->ifd[0],0)) < dz->wanted) {
  379. if(n <= count-2) {
  380. sprintf(errstr,"Program miscounted windows: anomaly 1 at EOF? : advance_along_input_windows()\n");
  381. return(PROGRAM_ERROR);
  382. }
  383. if(samps_read < 0) {
  384. sprintf(errstr,"Program miscounted windows: anomaly 2 at EOF? : advance_along_input_windows()\n");
  385. return(PROGRAM_ERROR);
  386. }
  387. return(FINISHED);
  388. }
  389. if(sloom)
  390. dz->total_samps_read += samps_read;
  391. }
  392. }
  393. if(atend) /* 6 */
  394. dz->flbufptr[4] = dz->flbufptr[3];
  395. return(CONTINUE);
  396. }
  397. /*************************** CALCULATE_NUMBER_OF_OUTPUT_WINDOWS ***************************
  398. *
  399. * Given a sequence of events of varying duration, where initial and
  400. * final durations are known, together with start and end times of the
  401. * total sequence, this function calculates the total number of events.
  402. *
  403. * NB
  404. * (1) Where the segment duration is increading, log(startwdur/edndur) is -ve,
  405. * so the returned count is -ve.
  406. * (2) Where segment duration is NOT changing, log(startwdur/endwdur), and hence dcount, would be zero.
  407. * This situation is trapped by first checking for (approx) equality of startwdur and endwdur
  408. * and calculating the count in simpler manner.
  409. */
  410. double calculate_number_of_output_windows(double startwdur,double endwdur,int totaldur)
  411. {
  412. double durdiff, dcount;
  413. if(flteq((durdiff = endwdur - startwdur),0.0)) {
  414. dcount = (double)totaldur/endwdur;
  415. return(dcount);
  416. }
  417. dcount = startwdur/endwdur;
  418. dcount = log(dcount);
  419. dcount *= (double)totaldur/durdiff;
  420. return(dcount);
  421. }
  422. /********* CALC_POSITION_OUTPUT_WDWS_RELATIVE_TO_INPUT_WDWS_FOR_DECREASING_STRETCH ************
  423. *
  424. * THE ARRAY OF positions has to be retrograded, but if we have more than
  425. * a single output-arrayfull of position values, we must start calculating
  426. * the output position array from the last input position, then invert those
  427. * positions so they are first positions, and so on!!!
  428. * (0) As the array is to be filled backwards, start calculating positions
  429. * from end of input. So end of first pass = end of input (= count).
  430. * (1) Find how many locations remain in output-position buffer.
  431. * (2) Start of first pass is this no of positions before end.
  432. * (3) If start is < 0 this means that all the positions in the current input
  433. * pass will fit in the output buffer in its current state, so we skip the
  434. * loop and go to (10), Otherwise...
  435. * (4) Mark the address in the output buffer where writing-values begins.
  436. * (5) Store in output buffer, the positions RELATIVE to start of this segment
  437. * of input values (i.e. relative to ZERO).
  438. * (6) Retrograde this time-interval set.
  439. * (7) Increment these relative values by startwindow, to give absolute
  440. * position values.
  441. * (8) Do the output, and reinitialise the output buffer pointer to start
  442. * of buffer. Reset new input-block end to START of previous block
  443. * (we're working backwards).
  444. * (9) Decrement start of block by size of output array.
  445. * (10) If either we did not enter the loop OR we have some input values
  446. * left on leaving the principle loop, calcuate output positions of
  447. * these items, and store in the output buffer (which will be flushed
  448. * either by next call to timestretch_this_segment() or, at end, by flushbuf()).
  449. */
  450. int calc_position_output_wdws_relative_to_input_wdws_for_decreasing_stretch
  451. (int *thatwindow,int startwindow,int count,int totaldur,double param0,double param1,double param2,dataptr dz)
  452. {
  453. int exit_status;
  454. int n, start, end = count; /* 0 */
  455. double *p, *startptr;
  456. int tofill = dz->ptr[TSTR_PEND] - dz->ptr[TSTR_PBUF]; /* 1 */
  457. start = count - tofill; /* 2 */
  458. while(start>=0) { /* 3 */
  459. startptr = dz->ptr[TSTR_PBUF]; /* 4 */
  460. for(n=start;n<end;n++) /* 5 */
  461. *(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2);
  462. /* 6 */
  463. if((exit_status = retrograde_sequence_of_time_intervals(totaldur - start,end - start,startptr,dz))<0)
  464. return(exit_status);
  465. for(p = startptr;p<dz->ptr[TSTR_PEND];p++)
  466. *p += (double)startwindow; /* 7 */
  467. if((exit_status = do_timestretching(thatwindow,dz->iparam[TSTR_ARRAYSIZE],dz))<0)
  468. return(exit_status);
  469. dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF]; /* 8 */
  470. end = start;
  471. start -= dz->iparam[TSTR_ARRAYSIZE]; /* 9 */
  472. }
  473. if(end) { /* 10 */
  474. startptr = dz->ptr[TSTR_PBUF];
  475. for(n=0;n<end;n++)
  476. *(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2);
  477. if((exit_status = retrograde_sequence_of_time_intervals(totaldur,end,startptr,dz))<0)
  478. return(exit_status);
  479. for(p = startptr;p<dz->ptr[TSTR_PBUF];p++)
  480. *p += (double)startwindow;
  481. }
  482. return(FINISHED);
  483. }
  484. /********* CALC_POSITION_OUTPUT_WDWS_RELATIVE_TO_INPUT_WDWS_FOR_INCREASING_STRETCH ************
  485. *
  486. * Find positions of output samples relative to input samples, buffer
  487. * by buffer.
  488. */
  489. int calc_position_output_wdws_relative_to_input_wdws_for_increasing_stretch
  490. (int *thatwindow,int startwindow,int count,double param0,double param1,double param2,dataptr dz)
  491. {
  492. int exit_status;
  493. int n;
  494. int start = 0;
  495. int end = dz->ptr[TSTR_PEND] - dz->ptr[TSTR_PBUF];
  496. while(count>=end) {
  497. for(n=start;n<end;n++)
  498. *(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2) + (double)startwindow;
  499. if((exit_status = do_timestretching(thatwindow,dz->iparam[TSTR_ARRAYSIZE],dz))<0)
  500. return(exit_status);
  501. dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];
  502. start = end;
  503. end += dz->iparam[TSTR_ARRAYSIZE];
  504. }
  505. if(count-start) {
  506. for(n=start;n<count;n++)
  507. *(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2) + (double)startwindow;
  508. }
  509. return(FINISHED);
  510. }
  511. /*************************** CALCULATE_POSITION ****************************
  512. *
  513. * Do the position calculation using the exponential formula.
  514. */
  515. double calculate_position(int x,double param0,double param1,double param2)
  516. {
  517. double k;
  518. k = param1;
  519. k *= (double)x;
  520. k = exp(k);
  521. k *= param2;
  522. k -= param2;
  523. return(k/(param0));
  524. }
  525. /*************************** RETROGRADE_SEQUENCE_OF_TIME_INTERVALS **************************
  526. *
  527. * Accepts a sequence of times, starting in address startptr,
  528. * and retrogrades the sequence of time-intervals, storing the
  529. * results back in startptr onwards.
  530. */
  531. int retrograde_sequence_of_time_intervals(int endtime,int count,double *startptr,dataptr dz)
  532. {
  533. double newtime, lasttime, tsize;
  534. int n;
  535. double *p = startptr;
  536. dz->ptr[TSTR_QBUF] = dz->parray[TSTR_QBUF] + (count-1);
  537. newtime = endtime;
  538. for(n=0;n<(count-1);n++) {
  539. lasttime = *p++;
  540. tsize = *p - lasttime;
  541. newtime -= tsize;
  542. *dz->ptr[TSTR_QBUF]-- = newtime;
  543. }
  544. if(dz->ptr[TSTR_QBUF]!=dz->parray[TSTR_QBUF]) {
  545. sprintf(errstr,"counting problem: retrograde_sequence_of_time_intervals()\n");
  546. return(PROGRAM_ERROR);
  547. }
  548. *dz->ptr[TSTR_QBUF] = *p; /* put starttime at start of intervals inverted array */
  549. p = startptr;
  550. for(n=0;n<count;n++)
  551. *p++ = *dz->ptr[TSTR_QBUF]++;
  552. return(FINISHED);
  553. }
  554. /**************************** SPECSTRETCH ***************************
  555. *
  556. * stretch the frq values in spectrum (e.g. harmonic -> inharmonic).
  557. */
  558. int specstretch(dataptr dz)
  559. {
  560. int exit_status;
  561. if(dz->brksize[STR_DEPTH] && flteq(dz->param[STR_DEPTH],0.0))
  562. return(FINISHED);
  563. if((exit_status = get_amp_and_frq(dz->flbufptr[0],dz))<0)
  564. return(exit_status);
  565. if(dz->brksize[STR_DEPTH])
  566. dz->param[STR_NSHIFT] = (dz->param[STR_SL1] * dz->param[STR_DEPTH]) + 1.0;
  567. if((exit_status = stretch_spectrum(dz->param[STR_NSHIFT],dz))<0)
  568. return(exit_status);
  569. if((exit_status = put_amp_and_frq(dz->flbufptr[0],dz))<0)
  570. return(exit_status);
  571. return(FINISHED);
  572. }
  573. /************************** STRETCH_SPECTRUM *****************************/
  574. int stretch_spectrum(double shift,dataptr dz)
  575. {
  576. int j, k, spectop ,specbot;
  577. double chshift, ratio, str_part;
  578. double slone, onels, flone;
  579. switch(dz->mode) {
  580. case(STRETCH_ABOVE): /* STRETCH SPECTRUM, above fdcno, BY SHIFT */
  581. if( shift >= 1.0) {
  582. slone = shift - 1.0;
  583. j = dz->clength - 1;
  584. str_part = (double)((dz->clength - 1) - dz->iparam[STR_FDCNO]);
  585. chshift = shift;
  586. k = round((double)j/chshift);
  587. while( k >= dz->iparam[STR_FDCNO]) {
  588. dz->amp[j] = dz->amp[k];
  589. dz->freq[j] = (float)chshift*dz->freq[k];
  590. if(--j <= dz->iparam[STR_FDCNO])
  591. break;
  592. ratio = (double)(j - dz->iparam[STR_FDCNO])/str_part;
  593. ratio = pow(ratio,dz->param[STR_EXP]);
  594. chshift = (ratio * (slone)) + 1.0;
  595. k = round((double)j/chshift);
  596. }
  597. } else {
  598. onels = 1.0 - shift;
  599. spectop = round((double)(dz->clength-1) * shift);
  600. str_part = (float)(spectop - dz->iparam[STR_FDCNO]);
  601. chshift = 1.0;
  602. k = dz->iparam[STR_FDCNO];
  603. j = k;
  604. while( (k <= (dz->clength-1)) && (j <=spectop)) {
  605. dz->amp[j] = dz->amp[k];
  606. dz->freq[j] = (float)chshift * dz->freq[k];
  607. j++;
  608. ratio = (double)(j - dz->iparam[STR_FDCNO])/str_part;
  609. ratio = pow(ratio,dz->param[STR_EXP]);
  610. chshift = 1.0 - (ratio * onels);
  611. k = round((double)j/chshift);
  612. }
  613. }
  614. break;
  615. case(STRETCH_BELOW): /* STRETCH SPECTRUM, below fdcno, DOWN BY SHIFT */
  616. flone = dz->iparam[STR_FDCNO] - 1;
  617. if(shift <= 1.0) {
  618. onels = 1.0 - shift;
  619. j = 1;
  620. k = round((double)j/shift);
  621. chshift = shift;
  622. while( k < dz->iparam[STR_FDCNO]) {
  623. dz->amp[j] = dz->amp[k];
  624. dz->freq[j] = (float)chshift*dz->freq[k];
  625. j++ ;
  626. ratio = (double)j/flone;
  627. ratio = pow(ratio,dz->param[STR_EXP]);
  628. chshift = shift + (ratio * onels);
  629. k = round((double)j/chshift);
  630. }
  631. } else {
  632. slone = shift - 1.0;
  633. j = dz->iparam[STR_FDCNO] - 1;
  634. k = j;
  635. specbot = round(shift);
  636. str_part = flone - (double)specbot;
  637. chshift = 1.0;
  638. while( (k > 0) && (j >= specbot)) {
  639. dz->amp[j] = dz->amp[k];
  640. dz->freq[j] = (float)chshift * dz->freq[k];
  641. j-- ;
  642. ratio = (flone - (double)j)/str_part;
  643. ratio = pow(ratio,dz->param[STR_EXP]);
  644. chshift = (ratio * slone) + 1.0;
  645. k = round((double)j/chshift);
  646. }
  647. }
  648. break;
  649. default:
  650. sprintf(errstr,"Unknown mode in stretch_spectrum()\n");
  651. return(PROGRAM_ERROR);
  652. }
  653. return(FINISHED);
  654. }