envel.c 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  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. /* floatsam version */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <structures.h>
  26. #include <tkglobals.h>
  27. #include <globcon.h>
  28. #include <processno.h>
  29. #include <modeno.h>
  30. #include <arrays.h>
  31. #include <envel.h>
  32. #include <cdpmain.h>
  33. //TW UPDATE
  34. #include <logic.h>
  35. #include <limits.h>
  36. #include <osbind.h>
  37. #include <sfsys.h>
  38. #define INBUF_START (0)
  39. #define OUTBUF_START (1)
  40. #define OUTBUF_END (2)
  41. static int init_outbuf
  42. (int startsamp,int *is_simple,int *write_offset,int *samp_offset,int *samps_left_to_process,dataptr dz);
  43. static int init_brkpnts
  44. (int *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk,
  45. double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
  46. static int advance_brkpnts
  47. (double starttime,double *gain,double *endbrk,double **nextbrk,double *nextgain,
  48. double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
  49. static int calc_samps_to_process
  50. (int *startsamp,int *samps_left_to_process,dataptr dz);
  51. static int simple_envel_processing
  52. (int *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain,
  53. int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
  54. static int buf_staggered_envel_processing
  55. (int *samps_left_to_process,int samp_offset,int write_offset,double starttime,double *endbrk,double **nextbrk,
  56. double *nextgain,int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
  57. static int read_partbuf_samps
  58. (int samps_to_read,int *samps_left_to_process, dataptr dz);
  59. static int do_envelope
  60. (int samp_cnt,double starttime,double *endbrk,double **nextbrk,double *nextgain,
  61. int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
  62. static int read_ssamps(int samps_to_read,int *samps_left_to_process,dataptr dz);
  63. static int do_simple_read(int *samps_left_to_process,int bufsize,dataptr dz);
  64. static int do_offset_read(int *samps_left_to_process,int samp_offset,int bufsize,dataptr dz);
  65. static int skip_into_file(int startsamp,int extended_buf_sampsize,int *write_offset,int *samp_offset,dataptr dz);
  66. /******************************* APPLY_BRKPNT_ENVELOPE *******************************/
  67. int apply_brkpnt_envelope(dataptr dz)
  68. {
  69. int exit_status;
  70. int startsamp, samps_left_to_process;
  71. int is_simple;
  72. int write_offset, samp_offset, sampno, nextbrk_sampno;
  73. double starttime, gain, nextgain, gain_step, gain_incr;
  74. double *endbrk, *nextbrk;
  75. if((exit_status = calc_samps_to_process(&startsamp,&samps_left_to_process,dz))<0)
  76. return(exit_status);
  77. if((exit_status = init_outbuf(startsamp,&is_simple,&write_offset,&samp_offset,&samps_left_to_process,dz))<0)
  78. return(exit_status);
  79. if((exit_status = init_brkpnts
  80. (&sampno,&starttime,&gain,&endbrk,&nextbrk,&nextgain,&gain_step,&gain_incr,&nextbrk_sampno,dz))<0)
  81. return(exit_status);
  82. exit_status = FINISHED;
  83. if(is_simple)
  84. exit_status = simple_envel_processing
  85. (&samps_left_to_process,starttime,endbrk,&nextbrk,&nextgain,
  86. &sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,dz);
  87. else
  88. exit_status = buf_staggered_envel_processing
  89. (&samps_left_to_process,samp_offset,write_offset,starttime,endbrk,&nextbrk,
  90. &nextgain,&sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,dz);
  91. return(exit_status);
  92. }
  93. /**************************** INIT_OUTBUF *******************************
  94. *
  95. * |-------------extended-buffer-size-----------|
  96. * X
  97. * |-------------buffer-size---------------|
  98. * INBUF
  99. * |----|----|----|----|----|----|----|----|----|
  100. * | | |
  101. * | | | |
  102. write (=write
  103. offset offset)
  104. * | | | |
  105. * | | |
  106. * samp |
  107. * offset |
  108. * | | |
  109. * |----|----|----|----|----|----|----|----|
  110. * OUTBUF
  111. * |-------------buffer-size---------------|
  112. *
  113. * IF the brkpoint table starts at 0,
  114. * we can use THE SAME buffer for input and output.
  115. * OTHERWISE.........
  116. * (8) First extimate of the number of samples in the input file which
  117. * we can skip, i.e. the number of complete extended-buffer-fulls
  118. * (see diagram) we can read before reaching first significant sample.
  119. * (9) After counting out these, we can assess how many COMPLETED sectors
  120. * are still to be read and ignored.
  121. * (10) We can now add the number of samples in these sectors to our first
  122. * estimate of samples to be skipped.
  123. * (11) The extent to which the OUTPUT buffer will be offset from the
  124. * INPUT buffer, (samp_offset) is given by the remaining part-sector of samps.
  125. * (see diagram).
  126. * (12) After the initial write, we will WRITE to a block 1 SECTOR later,
  127. * (X in diagram), so the WRITE-OFFSET is as shown.
  128. * (13) We now SEEK an exact number of sectors in the input file (thus
  129. * discarding these samps from our processing).
  130. * (14) If the samp_offset is ZERO, then we input and output buffers are
  131. * the same as at 4,5,6.
  132. * (16) Otherwise, fill the EXTENDED buffer (see diagram).
  133. * (17) Move the address of future read-ins (inbuf) 1 sector forward (to X in diagram).
  134. * (18) Set the address of the read-out buffer at the correct offset.
  135. * (19) Set the flag for the more difficult case.
  136. * (20) Decrement number of samps left to process.
  137. * If this takes samps_left below zero, this means we have
  138. * read a whole sector in place of a part-sector, so we must
  139. * readjust the value of samps_read!!
  140. */
  141. int init_outbuf(int startsamp,int *is_simple,int *write_offset,
  142. int *samp_offset,int *samps_left_to_process,dataptr dz)
  143. {
  144. int exit_status;
  145. int extended_buf_sampsize = dz->buflen;
  146. int shsecsize = F_SECSIZE;
  147. /*RWD: set the vars*/
  148. *samp_offset = *write_offset = 0;
  149. if(startsamp==0) { /* If we start at beginning */
  150. dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START]; /* inbuf and outbuf coincide */
  151. if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)
  152. return(exit_status); /* setup simple buffering option */
  153. *is_simple = TRUE;
  154. } else {
  155. if((exit_status = skip_into_file(startsamp,extended_buf_sampsize,write_offset,samp_offset,dz))<0)
  156. return(exit_status); /* calculate sectors to skip into file, and any part-sector offset, and skip */
  157. if(*samp_offset==0) { /* If no offset */
  158. dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START];/* inbuf and outbuf coincide */
  159. if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)
  160. return(exit_status);
  161. *is_simple = TRUE;
  162. } else { /* Otherwise there is an offset */
  163. if((exit_status = do_offset_read(samps_left_to_process,*samp_offset,
  164. /*dz->bigbufsize + SECSIZE*/dz->buflen,dz))<0)
  165. return(exit_status); /* read initial LARGE buffer */
  166. dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START] + *samp_offset;
  167. /* Set outbuf (write) position */
  168. dz->sampbuf[OUTBUF_END] = dz->sampbuf[OUTBUF_START] + dz->buflen;
  169. /* Set endpointer of outbuf */
  170. dz->sampbuf[INBUF_START] += shsecsize; /* Set next read position for inbuf */
  171. /* to permit correct wrap_around of part_sector */
  172. *is_simple = FALSE; /* Flag staggerd-buffers option */
  173. }
  174. }
  175. return(FINISHED);
  176. }
  177. /**************************** INIT_BRKPNTS *******************************
  178. * NB Here samples are taken to be a short for mono, 2 shorts for stereo, etc.
  179. * and times are measured in such 'samples'.
  180. */
  181. int init_brkpnts(int *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk,
  182. double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
  183. {
  184. double nexttime, time_from_start;
  185. int paramno = dz->extrabrkno;
  186. *endbrk = dz->brk[paramno] + ((dz->brksize[paramno]-1) * 2);
  187. *sampno = 0;
  188. *starttime = dz->brk[paramno][0];
  189. *gain = dz->brk[paramno][1];
  190. *nextbrk = dz->brk[paramno] + 2;
  191. nexttime = **nextbrk;
  192. *nextgain = *((*nextbrk) + 1);
  193. *gain_step = *nextgain - *gain;
  194. time_from_start = nexttime - *starttime;
  195. /* OCT 1996 */
  196. if((*nextbrk_sampno = (int)round(time_from_start * (double)dz->infile->srate))<0) {
  197. sprintf(errstr,"Impossible brkpoint time: (%.2lf secs)\n",time_from_start);
  198. return(PROGRAM_ERROR);
  199. }
  200. *gain_incr = (*gain_step)/(double)(*nextbrk_sampno);
  201. return(FINISHED);
  202. }
  203. /**************************** ADVANCE_BRKPNTS *****************************
  204. * NB Here samples are taken to be a short for mono, 2 shorts for stereo, etc.
  205. * and times are measured in such 'samples'.
  206. */
  207. int advance_brkpnts(double starttime,double *gain,double *endbrk,double **nextbrk,
  208. double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
  209. {
  210. double nexttime, time_from_start;
  211. int lastbrk_sampno, sampdist;
  212. if(*nextbrk!=endbrk) {
  213. *nextbrk += 2;
  214. *gain = *nextgain;
  215. nexttime = **nextbrk;
  216. *nextgain = *((*nextbrk) + 1);
  217. *gain_step = *nextgain - *gain;
  218. lastbrk_sampno = *nextbrk_sampno;
  219. time_from_start = nexttime - starttime;
  220. /* OCT 1996 */
  221. if((*nextbrk_sampno = (int)round(time_from_start * dz->infile->srate))<0) {
  222. sprintf(errstr,"Impossible brkpoint time: (%.2lf secs)\n",time_from_start);
  223. return(PROGRAM_ERROR);
  224. }
  225. sampdist = *nextbrk_sampno - lastbrk_sampno;
  226. *gain_incr = (*gain_step)/(double)sampdist;
  227. }
  228. return(FINISHED);
  229. }
  230. /************************ CALC_SAMPS_TO_PROCESS ****************************
  231. *
  232. * (1) Find time of final breakpoint value.
  233. * (a) Find the sample position of the brkpoint-table's starting time.
  234. * (b) Find its samp position.
  235. * (2) Find this time in samples (here samples mean short samples).
  236. * (3) The last samp to be processed is either the samp corresponding
  237. * to the last sample-time in brkpnt file OR the end of the input file.
  238. * (4) Number of samps-to-process = endsamp-time - startsamp-time.
  239. * (5) This also gives the required size of output file.
  240. */
  241. int calc_samps_to_process(int *startsamp,int *samps_left_to_process,dataptr dz)
  242. {
  243. int paramno = dz->extrabrkno;
  244. int endbrk_samptime, endsamp, start_samp;
  245. double lastbrktime, firstbrktime;
  246. double infiledur = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
  247. lastbrktime = *(dz->brk[paramno] + ((dz->brksize[paramno] - 1) * 2));
  248. if(flteq(lastbrktime,infiledur)) {
  249. endsamp = dz->insams[0];
  250. } else {
  251. endbrk_samptime = round(lastbrktime * (double)dz->infile->srate);
  252. endbrk_samptime *= dz->infile->channels;
  253. endsamp = min((int)endbrk_samptime,dz->insams[0]);
  254. }
  255. firstbrktime = *(dz->brk[paramno]);
  256. *startsamp = round(firstbrktime * (double)dz->infile->srate);
  257. *startsamp *= dz->infile->channels;
  258. if((start_samp = *startsamp ) >= dz->insams[0]) {
  259. sprintf(errstr,"envelope begins after end of file: can't proceed.\n");
  260. return(DATA_ERROR);
  261. }
  262. *samps_left_to_process = endsamp - start_samp;
  263. return(FINISHED);
  264. }
  265. /*********************** SIMPLE_ENVEL_PROCESSING ********************************
  266. *
  267. * Simple case, input and output buffers coincide.
  268. *
  269. * (1) If we read beyond number of samps we anticipated, this means
  270. * we have read to the end of a sector, where we need a part-sector,
  271. * so we must adjust value of actual samps read!!!
  272. */
  273. int simple_envel_processing
  274. (int *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain,
  275. int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
  276. {
  277. int exit_status;
  278. while(*samps_left_to_process > 0) {
  279. if((exit_status = do_envelope
  280. (dz->buflen,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
  281. return(exit_status);
  282. if((exit_status = write_samps(dz->sampbuf[OUTBUF_START],dz->buflen,dz))<0)
  283. return(exit_status);
  284. if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)
  285. return(exit_status);
  286. }
  287. if((exit_status = do_envelope
  288. (dz->ssampsread,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
  289. return(exit_status);
  290. if(dz->ssampsread > 0)
  291. return write_samps(dz->sampbuf[OUTBUF_START],dz->ssampsread,dz);
  292. return(FINISHED);
  293. }
  294. /*********************** BUF_STAGGERED_ENVEL_PROCESSING ********************************
  295. *
  296. * Non-simple case, input and output buffers do not coincide.
  297. *
  298. * ___________tail is copied thus_________
  299. * | |
  300. * | |
  301. * v INBUF ^
  302. * |----|----|----|----|----|----|----|----|----|
  303. * | |
  304. * | | | |
  305. * write_offset tail
  306. * | | | |
  307. * | |
  308. * |----|----|----|----|----|----|----|----|
  309. * OUTBUF
  310. *
  311. * (1) If we are inside the loop, there are still samps left to read
  312. * from input file, so this input buffer must be FULL.
  313. * This means we can WRITE a full output-buffer.
  314. * (2) Copy the tail-portion of the input buffer (that falls outside the
  315. * end of the output buffer (see diagram)), to the start of the output
  316. buffer (see diagram).
  317. * (3) Read samps to inbuf location, decrementing no of samps left to read.
  318. * (4) If first time, (No buffers written: samps were read into VERY START of buf)
  319. * no. of samps to write equals samps_read
  320. * MINUS those not needed, in samp_offset area.....
  321. * (5) After first time, (Buffers laready writ: samps now read into the displaced inbuf)
  322. * number of samps to write equals those read
  323. * PLUS those already in start of outbuffer, haing been copied back into the write_offset segment.
  324. * (6) Do envelope on the incomplete (or exactly full) buffer.
  325. * (7) Write this.
  326. */
  327. int buf_staggered_envel_processing
  328. (int *samps_left_to_process,int samp_offset,int write_offset,double starttime,double *endbrk,double **nextbrk,
  329. double *nextgain,int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
  330. {
  331. int exit_status;
  332. int samps_to_write_here;
  333. int firstime = TRUE;
  334. while(*samps_left_to_process > 0) {
  335. firstime = FALSE;
  336. if((exit_status = do_envelope
  337. (dz->buflen,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
  338. return(exit_status);
  339. if((exit_status = write_samps(dz->sampbuf[OUTBUF_START],dz->buflen,dz))<0)
  340. return(exit_status); /* 1 */
  341. memmove((char *)dz->sampbuf[OUTBUF_START],(char *)dz->sampbuf[OUTBUF_END],write_offset * sizeof(float));
  342. if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)
  343. return(exit_status); /* 3 */
  344. }
  345. if(firstime)
  346. samps_to_write_here = dz->ssampsread - samp_offset; /* 4 */
  347. else
  348. samps_to_write_here = dz->ssampsread + write_offset; /* 5 */
  349. if((exit_status = do_envelope /* 6 */
  350. (samps_to_write_here,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
  351. return(exit_status);
  352. /* 7 */
  353. if(samps_to_write_here > 0)
  354. return write_samps(dz->sampbuf[OUTBUF_START],samps_to_write_here,dz);
  355. return(FINISHED);
  356. }
  357. /**************************** READ_PARTBUF_SAMPS *****************************/
  358. int read_partbuf_samps(int samps_to_read,int *samps_left_to_process, dataptr dz)
  359. {
  360. if((dz->ssampsread = fgetfbufEx(dz->sampbuf[INBUF_START], samps_to_read,dz->ifd[0],0)) < 0) {
  361. sprintf(errstr,"Can't read samples from input soundfile: read_partbuf_samps()\n");
  362. return(SYSTEM_ERROR);
  363. }
  364. if(dz->ssampsread < samps_to_read) {
  365. sprintf(errstr,"Error in buffering arithmetic: read_partbuf_samps()\n");
  366. return(PROGRAM_ERROR);
  367. }
  368. *samps_left_to_process -= dz->ssampsread;
  369. return(FINISHED);
  370. }
  371. /************************* DO_ENVELOPE ********************************
  372. *
  373. * (1) endsampno (absolute numbering) is the final sample to be treated in this call.
  374. *
  375. * While ever the quit-flag is not set...
  376. * (2) if the sample number of the next break-pnt falls before or at the end
  377. * of this function call...
  378. * Set the 'change' flag, which will cause envelope breakpoints to be
  379. * advanced.
  380. * (3) set end of the inner-loop pass to this next brkpnt.
  381. * (4) If the brkpnt falls exactly at end of pass, set the 'quit' flag.
  382. * Otherwise quit remains FALSE, and the outer loop will be recalled (after
  383. * breakpoints have been advanced).
  384. * (5) Otherwise, the next breakpnt falls beyond the end of this function call.
  385. * So don't advance the breakpoints (change = FALSE), sample at end of inner
  386. * loop (this_endsamp) is the sample at end of this call-to-function
  387. * (endsampno), AND set flag to quit at end of inner loop.
  388. * (6) Counter for inner loop is this-endsamp minus current position (sampno).
  389. * (7) Inner loop, get gain for each sample, and increment samples accordingly.
  390. * (8) Increment the absolute count of processed samples (sampno).
  391. * (9) If change flag is set, reset gain and advance breakpoints.
  392. * (10) Retain the enveloping gain current at end of buffer.
  393. */
  394. int do_envelope
  395. (int samp_cnt,double starttime,double *endbrk,double **nextbrk,double *nextgain,
  396. int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
  397. {
  398. int exit_status;
  399. int n, m, sampcnt;
  400. int endsampno, this_endsamp, this_sampcnt;
  401. float *obuf = dz->sampbuf[OUTBUF_START];
  402. float *obufend = obuf + dz->buflen;
  403. int quit = FALSE, change;
  404. double val;
  405. double this_gain = *gain;
  406. double this_gain_incr = *gain_incr;
  407. double this_gain_step = *gain_step;
  408. sampcnt = samp_cnt / dz->infile->channels; /* 'stereo'-samples to process */
  409. endsampno = *sampno + sampcnt; /* 1 */
  410. if(sampcnt * dz->infile->channels > dz->buflen) {
  411. sprintf(errstr,"Buffering anomaly: do_envelope()\n");
  412. return(PROGRAM_ERROR);
  413. }
  414. while(quit==FALSE) {
  415. if(*nextbrk_sampno <= endsampno) { /* 2 */
  416. change = TRUE;
  417. this_endsamp = *nextbrk_sampno; /* 3 */
  418. if(*nextbrk_sampno==endsampno)
  419. quit = TRUE; /* 4 */
  420. } else {
  421. change = FALSE; /* 5 */
  422. this_endsamp = endsampno;
  423. quit = TRUE;
  424. }
  425. this_sampcnt = this_endsamp - *sampno; /* 6 */
  426. if(obuf + (this_sampcnt * dz->infile->channels) > obufend) {
  427. sprintf(errstr,"array overrun: do_envelope()\n");
  428. return(PROGRAM_ERROR);
  429. }
  430. if(flteq(this_gain,1.0) && flteq(this_gain_step,0.0))
  431. obuf += this_sampcnt * dz->infile->channels; /* no modification of sound */
  432. else {
  433. for(n=0;n<this_sampcnt;n++) { /* 7 */
  434. this_gain += this_gain_incr;
  435. for(m=0;m<dz->infile->channels;m++) {
  436. val = /*round*/((double)(*obuf) * this_gain);
  437. *obuf = (float)val;
  438. obuf++;
  439. }
  440. }
  441. }
  442. *sampno += this_sampcnt; /* 8 */
  443. if(change) { /* 9 */
  444. if((exit_status = advance_brkpnts
  445. (starttime,gain,endbrk,nextbrk,nextgain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
  446. return(exit_status);
  447. this_gain = *gain;
  448. this_gain_incr = *gain_incr;
  449. this_gain_step = *gain_step;
  450. }
  451. }
  452. *gain = this_gain; /* 10 */
  453. return(FINISHED);
  454. }
  455. /************************* READ_SSAMPS ******************************/
  456. int read_ssamps(int samps_to_read,int *samps_left_to_process,dataptr dz)
  457. {
  458. if((dz->ssampsread = fgetfbufEx(dz->sampbuf[INBUF_START], samps_to_read,dz->ifd[0],0)) < 0) {
  459. sprintf(errstr,"Can't read samples from input soundfile: read_ssamps()\n");
  460. return(SYSTEM_ERROR);
  461. }
  462. if(dz->ssampsread!=samps_to_read) {
  463. sprintf(errstr,"Error in buffering arithmetic: read_ssamps()\n");
  464. return(PROGRAM_ERROR);
  465. }
  466. *samps_left_to_process -= dz->ssampsread;
  467. return(FINISHED);
  468. }
  469. /******************************** DO_SIMPLE_READ **********************************/
  470. int do_simple_read(int *samps_left_to_process,int bufsize,dataptr dz)
  471. {
  472. int exit_status;
  473. if(*samps_left_to_process < bufsize)
  474. exit_status = read_partbuf_samps(*samps_left_to_process,samps_left_to_process,dz);
  475. else
  476. exit_status = read_ssamps(bufsize,samps_left_to_process,dz);
  477. return(exit_status);
  478. }
  479. /******************************** DO_OFFSET_READ **********************************/
  480. int do_offset_read(int *samps_left_to_process,int samp_offset,int bufsize,dataptr dz)
  481. {
  482. int exit_status;
  483. if(*samps_left_to_process < bufsize) {
  484. exit_status = read_partbuf_samps(*samps_left_to_process + samp_offset,samps_left_to_process,dz);
  485. *samps_left_to_process = 0;
  486. } else {
  487. exit_status = read_ssamps(bufsize,samps_left_to_process,dz);
  488. *samps_left_to_process += samp_offset; /* some of samps-read are not part of samps-to-process */
  489. }
  490. return(exit_status);
  491. }
  492. /******************************** SKIP_INTO_FILE **********************************/
  493. //RWD ugh! unless this is simply a sndseek to startsamp....
  494. //TW unfortunately, it's intrinsically tied up with old buffering scheme
  495. //#ifdef NOTDEF
  496. int skip_into_file(int startsamp,int extended_buf_sampsize,int *write_offset,int *samp_offset,dataptr dz)
  497. {
  498. int skipsamps=(startsamp/extended_buf_sampsize) * extended_buf_sampsize; /* 8 */
  499. int sampsecsize = ENV_FSECSIZE;
  500. int sectors_remaining = (startsamp - skipsamps)/sampsecsize; /* 9 */
  501. skipsamps += sectors_remaining * sampsecsize; /* 10 */
  502. *samp_offset = startsamp - skipsamps; /* 11 */
  503. *write_offset = ENV_FSECSIZE - *samp_offset; /* 12 */
  504. if(sndseekEx(dz->ifd[0],skipsamps,0)<0) { /* 13 */
  505. sprintf(errstr,": sndseekEx failed: skip_into_file()\n");
  506. return(SYSTEM_ERROR);
  507. }
  508. return(FINISHED);
  509. }
  510. //#endif
  511. //TW UPDATE: NEW CODE
  512. /*** NEW april 2002 ****/
  513. static int fill_grid_array(double starttime,int *firstpass, double *next_gridstart, double **d, int *arraysize, dataptr dz);
  514. static int check_available_space(dataptr dz);
  515. static int create_grid_envelope(int n, double *next_gridstart,dataptr dz);
  516. static int do_grid_envelope(dataptr dz);
  517. static int do_grid_biz(int sib,int eib,int style,int *splicepos,dataptr dz);
  518. static void get_nextposition_pair(double *ds,int *startsamp,int *endsamp,int *style,dataptr dz);
  519. #define GRID_ZERO (0)
  520. #define GRID_COPY (1)
  521. #define GRID_DOWN (2)
  522. #define GRID_UP (3)
  523. /************************************ DO_GRIDS ********************************/
  524. int do_grids(dataptr dz)
  525. {
  526. int exit_status;
  527. int n;
  528. int namelen, numlen;
  529. char *outfilename;
  530. //TW REVISION DEc 2002
  531. // char *outfilenumber;
  532. char *p, *q, *r;
  533. double next_gridstart;
  534. numlen = 4;
  535. if(!sloom) {
  536. namelen = strlen(dz->wordstor[0]);
  537. q = dz->wordstor[0];
  538. r = dz->wordstor[0] + namelen;
  539. p = r - 1;
  540. while((*p != '\\') && (*p != '/') && (*p != ':')) {
  541. p-- ;
  542. if(p < dz->wordstor[0])
  543. break;
  544. }
  545. if(p > dz->wordstor[0]) {
  546. p++;
  547. while(p <= r)
  548. *q++ = *p++;
  549. }
  550. }
  551. namelen = strlen(dz->wordstor[0]);
  552. // if(sndunlink(dz->ofd) < 0) {
  553. // fprintf(stdout,"WARNING: Can't set initial dummy output soundfile for deletion.\n");
  554. // fflush(stdout);
  555. // }
  556. // if(sndcloseEx(dz->ofd) < 0) {
  557. // fprintf(stdout,"ERROR: Can't close initial dummy output soundfile\n");
  558. // return(SYSTEM_ERROR);
  559. // }
  560. dz->ofd = -1;
  561. if((exit_status = check_available_space(dz))<0)
  562. return(exit_status);
  563. if((dz->tempsize = dz->insams[0] * dz->iparam[GRID_COUNT])<0)
  564. dz->tempsize = INT_MAX;
  565. if(sloom)
  566. namelen--; /* Drop the 0 at end of name */
  567. next_gridstart = 0.0;
  568. if((exit_status = reset_peak_finder(dz))<0)
  569. return(exit_status);
  570. for(n=0;n<dz->iparam[GRID_COUNT];n++) {
  571. if(sndseekEx(dz->ifd[0],0,0)<0) {
  572. sprintf(errstr,"sndseekEx() failed.\n");
  573. return(SYSTEM_ERROR);
  574. }
  575. reset_filedata_counters(dz);
  576. // FEB 2010 TW
  577. if((outfilename = (char *)malloc((namelen + numlen + 10) * sizeof(char)))==NULL) {
  578. sprintf(errstr,"INSUFFICIENT MEMORY for outfilename.\n");
  579. return(MEMORY_ERROR);
  580. }
  581. strcpy(outfilename,dz->wordstor[0]);
  582. //TW REvision Dec 2002
  583. if(sloom)
  584. insert_new_number_at_filename_end(outfilename,n,1);
  585. // FEB 2010 TW
  586. else {
  587. insert_separator_on_sndfile_name(outfilename,1);
  588. insert_new_number_at_filename_end(outfilename,n,0);
  589. }
  590. dz->process_type = EQUAL_SNDFILE; /* allow sndfile to be created */
  591. if((exit_status = create_sized_outfile(outfilename,dz))<0) {
  592. if(!sloom) {
  593. sprintf(errstr, "Soundfile %s already exists: Made %d grids only.\n",outfilename,n-1);
  594. free(outfilename);
  595. dz->process_type = OTHER_PROCESS;
  596. dz->ofd = -1;
  597. return(GOAL_FAILED);
  598. } else {
  599. dz->process_type = OTHER_PROCESS;
  600. dz->ofd = -1;
  601. sprintf(errstr, "Soundfile %s already exists: Made %d grids only.\n",outfilename,n-1);
  602. return(SYSTEM_ERROR);
  603. }
  604. }
  605. dz->process_type = OTHER_PROCESS;
  606. if((exit_status = create_grid_envelope(n,&next_gridstart,dz))<0)
  607. return(exit_status);
  608. if((exit_status = do_grid_envelope(dz))<0)
  609. return(exit_status);
  610. dz->process_type = EQUAL_SNDFILE; /* allows header to be written */
  611. dz->outfiletype = SNDFILE_OUT; /* allows header to be written */
  612. if((exit_status = headwrite(dz->ofd,dz))<0) {
  613. free(outfilename);
  614. return(exit_status);
  615. }
  616. dz->process_type = OTHER_PROCESS; /* restore true status */
  617. dz->outfiletype = NO_OUTPUTFILE; /* restore true status */
  618. if((exit_status = reset_peak_finder(dz))<0)
  619. return(exit_status);
  620. if(sndcloseEx(dz->ofd) < 0) {
  621. fprintf(stdout,"WARNING: Can't close output soundfile %s\n",outfilename);
  622. fflush(stdout);
  623. }
  624. free(outfilename);
  625. dz->ofd = -1;
  626. }
  627. return(FINISHED);
  628. }
  629. /************************************ CHECK_AVAILABLE_SPACE ********************************/
  630. #define LEAVESPACE (10*1024)
  631. int check_available_space(dataptr dz)
  632. {
  633. unsigned int slots;
  634. unsigned int freespace = getdrivefreespace("temp") - LEAVESPACE;
  635. freespace /= sizeof(float);
  636. slots = freespace/dz->insams[0];
  637. if(slots < (unsigned int)dz->iparam[COPY_CNT]) {
  638. sprintf(errstr,"Insufficient space on disk to create %d copies.\n"
  639. "You have space for %d copies.\n",dz->iparam[COPY_CNT],slots);
  640. return(GOAL_FAILED);
  641. }
  642. return(FINISHED);
  643. }
  644. /************************************ CREATE_GRID_ENVELOPE ********************************/
  645. int create_grid_envelope(int n, double *next_gridstart,dataptr dz)
  646. {
  647. double *d, time, thistime, grid_step, half_gridsplen;
  648. int arraysize = 8, old_arraysize;
  649. double starttime;
  650. int firstpass, exit_status;
  651. if(dz->brksize[GRID_WIDTH] == 0) {
  652. grid_step = dz->param[GRID_WIDTH] * dz->iparam[GRID_COUNT];
  653. switch(n) {
  654. case(0):
  655. if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
  656. sprintf(errstr,"Insufficient memory for grid envelope,\n");
  657. return(MEMORY_ERROR);
  658. }
  659. d = dz->parray[0];
  660. for(time = 0.0; time <= dz->duration; time += grid_step) {
  661. thistime = time;
  662. if(flteq(time,0.0))
  663. *d++ = thistime;
  664. else {
  665. if(dz->brksize[GRID_SPLEN] > 0)
  666. read_value_from_brktable(thistime,GRID_SPLEN,dz);
  667. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  668. *d++ = thistime + half_gridsplen;
  669. }
  670. *d++ = 1.0;
  671. thistime += dz->param[GRID_WIDTH];
  672. if(dz->brksize[GRID_SPLEN] > 0)
  673. read_value_from_brktable(thistime,GRID_SPLEN,dz);
  674. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  675. *d++ = thistime - half_gridsplen;
  676. *d++ = 1.0;
  677. *d++ = thistime + half_gridsplen;
  678. *d++ = 0.0;
  679. thistime = time + grid_step;
  680. if(dz->brksize[GRID_SPLEN] > 0) {
  681. read_value_from_brktable(thistime,GRID_SPLEN,dz);
  682. }
  683. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  684. *d++ = thistime - half_gridsplen;
  685. *d++ = 0.0;
  686. old_arraysize = arraysize;
  687. arraysize += 8;
  688. if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize * sizeof(double)))==NULL) {
  689. sprintf(errstr,"Insufficient memory for grid envelope,\n");
  690. return(MEMORY_ERROR);
  691. }
  692. d = dz->parray[0] + old_arraysize;
  693. dz->parray[1] = d; /* mark end of parray */
  694. }
  695. break;
  696. case(1):
  697. for(d = dz->parray[1]-2; d >= dz->parray[0];d -= 2) {
  698. *(d+4) = (*d) + dz->param[GRID_WIDTH]; /* add time to values, and shift them up two brkpnt places */
  699. *(d+5) = *(d+1);
  700. }
  701. *(dz->parray[0]) = 0.0; /* Insert a zero time zero val */
  702. *(dz->parray[0]+1) = 0.0;
  703. if(dz->brksize[GRID_SPLEN] > 0) { /* And a splice-start zero */
  704. read_value_from_brktable(*(dz->parray[0]+4),GRID_SPLEN,dz);
  705. }
  706. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  707. *(dz->parray[0]+2) = *(dz->parray[0]+4) - half_gridsplen;
  708. *(dz->parray[0]+3) = 0.0;
  709. *(dz->parray[0]+4) += half_gridsplen;
  710. dz->parray[1] += 4; /* mark end of parray */
  711. break;
  712. default: /* move grid by grid-width, except zerotime point */
  713. for(d = dz->parray[1]-2; d >= dz->parray[0]+2;d -= 2)
  714. *d += dz->param[GRID_WIDTH];
  715. break;
  716. }
  717. } else {
  718. switch(n) {
  719. case(0):
  720. starttime = 0.0;
  721. firstpass = 1;
  722. if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
  723. sprintf(errstr,"Insufficient memory for grid envelope,\n");
  724. return(MEMORY_ERROR);
  725. }
  726. d = dz->parray[0];
  727. if((exit_status = fill_grid_array(starttime,&firstpass,next_gridstart,&d,&arraysize,dz))<0)
  728. return(exit_status);
  729. arraysize += 64; /* safety */
  730. if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize * sizeof(double)))==NULL) {
  731. sprintf(errstr,"Insufficient memory for grid envelope,\n");
  732. return(MEMORY_ERROR);
  733. }
  734. break;
  735. default: /* move grid by grid-width, except zerotime point */
  736. arraysize = 12;
  737. starttime = *next_gridstart;
  738. firstpass = 1;
  739. d = dz->parray[0] + 4;
  740. if((exit_status = fill_grid_array(starttime,&firstpass,next_gridstart,&d,&arraysize,dz))<0)
  741. return(exit_status);
  742. *(dz->parray[0]) = 0.0; /* Insert a zero time zero val */
  743. *(dz->parray[0]+1) = 0.0;
  744. if(dz->brksize[GRID_SPLEN] > 0) /* And a splice-start zero */
  745. read_value_from_brktable(*(dz->parray[0]+4),GRID_SPLEN,dz);
  746. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  747. *(dz->parray[0]+2) = *(dz->parray[0]+4) - half_gridsplen;
  748. *(dz->parray[0]+3) = 0.0;
  749. *(dz->parray[0]+4) += half_gridsplen;
  750. break;
  751. }
  752. }
  753. return(FINISHED);
  754. }
  755. /************************************ FILL_GRID_ARRAY ********************************/
  756. int fill_grid_array(double starttime,int *firstpass, double *next_gridstart, double **d, int *arraysize, dataptr dz)
  757. {
  758. double grid_step = 0.0, time, thistime, start_gridwidth, this_gridwidth, half_gridsplen = 0.0;
  759. int z;
  760. int k; //old_arraysize;
  761. for(time = starttime; time <=dz->duration; time += grid_step) {
  762. grid_step = 0.0;
  763. thistime = time;
  764. read_value_from_brktable(thistime,GRID_WIDTH,dz);
  765. start_gridwidth = dz->param[GRID_WIDTH];
  766. if(*firstpass) /* save initial distance to next grid set */
  767. *next_gridstart += start_gridwidth;
  768. this_gridwidth = start_gridwidth;
  769. grid_step += this_gridwidth;
  770. thistime += this_gridwidth;
  771. for(z=1;z<dz->iparam[GRID_COUNT];z++) { /*sum steps of all grids to get step from */
  772. read_value_from_brktable(thistime,GRID_WIDTH,dz); /* current window of this grid, to next window of this grid */
  773. this_gridwidth = dz->param[GRID_WIDTH];
  774. grid_step += this_gridwidth;
  775. thistime += this_gridwidth;
  776. }
  777. thistime = time;
  778. if(*firstpass)
  779. half_gridsplen = 0.0; /* Envelope starts without splice ... splice added in calling routine */
  780. else if(dz->brksize[GRID_SPLEN] > 0) {
  781. read_value_from_brktable(thistime,GRID_SPLEN,dz);
  782. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  783. }
  784. **d = thistime + half_gridsplen;
  785. (*d)++;
  786. **d = 1.0;
  787. (*d)++;
  788. thistime += start_gridwidth;
  789. if(dz->brksize[GRID_SPLEN] > 0) {
  790. read_value_from_brktable(thistime,GRID_SPLEN,dz);
  791. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  792. } else if(*firstpass)
  793. half_gridsplen = dz->param[GRID_SPLEN]/2.0; /* if no brkpnt table, only need to calc on first pass */
  794. *firstpass = 0;
  795. **d = thistime - half_gridsplen;
  796. (*d)++;
  797. **d = 1.0;
  798. (*d)++;
  799. **d = thistime + half_gridsplen;
  800. (*d)++;
  801. **d = 0.0;
  802. (*d)++;
  803. thistime = time + grid_step;
  804. if(dz->brksize[GRID_SPLEN] > 0) {
  805. read_value_from_brktable(thistime,GRID_SPLEN,dz);
  806. half_gridsplen = dz->param[GRID_SPLEN]/2.0;
  807. }
  808. **d = thistime - half_gridsplen;
  809. (*d)++;
  810. **d = 0.0;
  811. (*d)++;
  812. //old_arraysize = *arraysize;
  813. *arraysize += 8;
  814. k = *d - dz->parray[0];
  815. if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],(*arraysize) * sizeof(double)))==NULL) {
  816. sprintf(errstr,"Insufficient memory for grid envelope,\n");
  817. return(MEMORY_ERROR);
  818. }
  819. *d = dz->parray[0] + k;
  820. dz->parray[1] = *d; /* mark end of parray */
  821. }
  822. return(FINISHED);
  823. }
  824. /************************************ DO_GRID_ENVELOPE ********************************/
  825. int do_grid_envelope(dataptr dz)
  826. {
  827. double *ds = dz->parray[0];
  828. int sib, eib; /* startpos-ion-buf, edipos-in-buf */
  829. int style, exit_status, finished= 0;
  830. int startsamp, endsamp, splicepos = 0,last_total_samps_read = 0;
  831. sndseekEx(dz->ifd[0],0,0);
  832. get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz);
  833. sib = startsamp - last_total_samps_read;
  834. eib = endsamp - last_total_samps_read;
  835. if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0)
  836. return(exit_status);
  837. if(dz->ssampsread == 0) {
  838. sprintf(errstr,"No data found in input soundfile\n");
  839. return(GOAL_FAILED);
  840. }
  841. while(ds < dz->parray[1] - 2) {
  842. do {
  843. while(eib < dz->ssampsread) {
  844. do_grid_biz(sib,eib,style,&splicepos,dz);
  845. if((ds += 2) >= dz->parray[1] - 2) {
  846. finished = 1;
  847. break;
  848. }
  849. get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz);
  850. sib = startsamp - last_total_samps_read;
  851. eib = endsamp - last_total_samps_read;
  852. }
  853. if(finished)
  854. break;
  855. do_grid_biz(sib,dz->ssampsread,style,&splicepos,dz);
  856. if(dz->ssampsread > 0) {
  857. if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0)
  858. return(exit_status);
  859. }
  860. last_total_samps_read = dz->total_samps_read;
  861. if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0)
  862. return(exit_status);
  863. if(dz->ssampsread == 0) {
  864. finished = 1;
  865. break;
  866. }
  867. sib = 0;
  868. eib = endsamp - last_total_samps_read;
  869. if(eib == 0) {
  870. if((ds += 2) >= dz->parray[1] - 2) {
  871. finished = 1;
  872. break;
  873. }
  874. get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz);
  875. sib = startsamp - last_total_samps_read;
  876. eib = endsamp - last_total_samps_read;
  877. }
  878. } while(!finished);
  879. if(finished)
  880. break;
  881. }
  882. if(dz->ssampsread > 0) {
  883. if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0)
  884. return(exit_status);
  885. }
  886. return(FINISHED);
  887. }
  888. /************************************ DO_GRID_BIZ ********************************/
  889. int do_grid_biz(int sib,int eib,int style,int *splicepos,dataptr dz)
  890. {
  891. double splice_incr, splice_val;
  892. int n;
  893. switch(style) {
  894. case(GRID_ZERO): memset((char *)(dz->sampbuf[0] + sib),0,(eib - sib) * sizeof(float)); break;
  895. case(GRID_COPY): break;
  896. case(GRID_UP):
  897. dz->iparam[GRID_SPLEN] = (int)round(dz->param[GRID_SPLEN] * dz->infile->srate) * dz->infile->channels;
  898. splice_incr = 1.0 / (double)dz->iparam[GRID_SPLEN];
  899. splice_val = *splicepos * splice_incr;
  900. for(n = sib; n < eib; n++) {
  901. dz->sampbuf[0][n] = (float)(dz->sampbuf[0][n] * splice_val);
  902. splice_val += splice_incr;
  903. (*splicepos)++;
  904. }
  905. if(*splicepos >= dz->iparam[GRID_SPLEN])
  906. *splicepos = 0;
  907. break;
  908. case(GRID_DOWN):
  909. dz->iparam[GRID_SPLEN] = (int)round(dz->param[GRID_SPLEN] * dz->infile->srate) * dz->infile->channels;
  910. splice_incr = 1.0 / (double)dz->iparam[GRID_SPLEN];
  911. splice_val = 1.0 - (*splicepos * splice_incr);
  912. for(n = sib; n < eib; n++) {
  913. dz->sampbuf[0][n] = (float)(dz->sampbuf[0][n] * splice_val);
  914. splice_val -= splice_incr;
  915. (*splicepos)++;
  916. }
  917. if(*splicepos >= dz->iparam[GRID_SPLEN])
  918. *splicepos = 0;
  919. break;
  920. }
  921. return(FINISHED);
  922. }
  923. /************************************ GET_NEXTPOSITION_PAIR ********************************/
  924. void get_nextposition_pair(double *ds,int *startsamp,int *endsamp,int *style,dataptr dz)
  925. {
  926. double *de = ds+2, startval, endval;
  927. *startsamp = round(*ds * dz->infile->srate) * dz->infile->channels;
  928. *endsamp = round(*de * dz->infile->srate) * dz->infile->channels;
  929. startval = *(ds+1);
  930. endval = *(de+1);
  931. if(flteq(startval,1.0)) {
  932. if(flteq(endval,1.0))
  933. *style = GRID_COPY;
  934. else
  935. *style = GRID_DOWN;
  936. } else {
  937. if(flteq(endval,1.0))
  938. *style = GRID_UP;
  939. else
  940. *style = GRID_ZERO;
  941. }
  942. }