envimpos.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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. /* floatsam version */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <structures.h>
  25. #include <tkglobals.h>
  26. #include <globcon.h>
  27. #include <processno.h>
  28. #include <modeno.h>
  29. #include <arrays.h>
  30. #include <envel.h>
  31. #include <cdpmain.h>
  32. #include <sfsys.h>
  33. static void apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,
  34. int *cnt,float **envptr,double *step,float *thisval,
  35. float *nextval,int incr_cnt,int chans,dataptr dz);
  36. static void apply_env_to_window(int incr_cnt,double step, float startval,
  37. int startsamp,int chans,int is_log,dataptr dz);
  38. static void step_gen(float *thisval,float *nextval,double *step,float **envptr,int *is_log,int incr_cnt);
  39. static int reset_file_pos_and_counters(int fileno,dataptr dz);
  40. static void test_apply_env_to_window(int incr_cnt,double step,float startval,
  41. int startsamp,int chans,int is_log,double *maxval,dataptr dz);
  42. static void test_apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,int *cnt,
  43. float **envptr,double *step,float *thisval,float *nextval,int incr_cnt,int chans,
  44. double *maxval,dataptr dz);
  45. static int test_impose_envel_on_sndfile(float *env,int envcnt,int bufcnt,int fileno,double *maxval,dataptr dz);
  46. static void adjust_envelope(double adjuster,int envcnt,dataptr dz);
  47. /*************************** IMPOSE_ENVEL [APPLY_THE_ENV] *************************
  48. *
  49. * WE Assume that buffersizes have been recalcd etc by this stage,
  50. * and that they were last-calculated for the CURRENT file!!
  51. *
  52. * envcnt MUST BE the TRUE length of the NEW envelope!!!
  53. */
  54. int impose_envel_on_sndfile(float *env,int envcnt,int bufcnt,int fileno,dataptr dz)
  55. {
  56. int exit_status;
  57. int n, cnt;
  58. double maxval = 0.0;
  59. int envwindow_sampsize = dz->iparam[ENV_SAMP_WSIZE];
  60. int chans = dz->infile->channels;
  61. int incr_cnt = envwindow_sampsize/chans;
  62. float *envptr = env;
  63. double step;
  64. float thisval = *envptr;
  65. float nextval = *envptr;
  66. if((exit_status = reset_file_pos_and_counters(fileno,dz))<0)
  67. return(exit_status);
  68. if(sloom) {
  69. fprintf(stdout,"INFO: Testing levels of new envelope.\n");
  70. fflush(stdout);
  71. }
  72. if((exit_status = test_impose_envel_on_sndfile(env,envcnt,bufcnt,fileno,&maxval,dz))<0)
  73. return(exit_status);
  74. if(maxval > F_MAXSAMP)
  75. adjust_envelope(F_MAXSAMP/maxval,envcnt,dz);
  76. envptr = env;
  77. thisval = *envptr;
  78. nextval = *envptr;
  79. cnt = 0;
  80. if((exit_status = reset_file_pos_and_counters(fileno,dz))<0)
  81. return(exit_status);
  82. if(sloom) {
  83. fprintf(stdout,"INFO: Imposing new envelope on sound.\n");
  84. fflush(stdout);
  85. }
  86. for(n = 0; n < bufcnt; n++) {
  87. if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
  88. return(exit_status);
  89. apply_envel_to_buffer
  90. (dz->ssampsread,envwindow_sampsize,envcnt,&cnt,&envptr,&step,&thisval,&nextval,incr_cnt,chans,dz);
  91. if(dz->ssampsread > 0) {
  92. if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0)
  93. return(exit_status);
  94. }
  95. }
  96. return(FINISHED);
  97. }
  98. /******************************* APPLY_ENVEL_TO_BUFFER [ENVAPPLY] ******************************
  99. *
  100. * Apply envelope to input soundfile, to produce output sound file.
  101. *
  102. * If envelope table runs out before sound, last value in table is held.
  103. */
  104. void apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,
  105. int *cnt,float **envptr,double *step,float *thisval,float *nextval,int incr_cnt,
  106. int chans,dataptr dz)
  107. {
  108. int is_log = FALSE;
  109. int startsamp = 0;
  110. while(samps_to_process >= envwindow_sampsize) {
  111. if(++(*cnt) < envcnt)
  112. step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
  113. else {
  114. *thisval = *nextval;
  115. *step = 0.0; /* retain last envelope value if we run out of values */
  116. is_log = FALSE;
  117. }
  118. apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,dz);
  119. startsamp += envwindow_sampsize;
  120. samps_to_process -= envwindow_sampsize;
  121. }
  122. if(samps_to_process) { /* Handle any final short buffer */
  123. if(++(*cnt) < envcnt)
  124. step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
  125. else {
  126. *thisval = *nextval;
  127. *step = 0.0; /* retain last envelope value if we run out of values */
  128. is_log = FALSE;
  129. }
  130. incr_cnt = samps_to_process/chans;
  131. apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,dz);
  132. }
  133. return;
  134. }
  135. /************************ APPLY_ENV_TO_WINDOW [DO_THE_ENV] ***********************/
  136. void apply_env_to_window
  137. (int incr_cnt,double step, float startval, int startsamp,int chans,int is_log,dataptr dz)
  138. {
  139. int i, offset, bufpos;
  140. int chanpos;
  141. double newval, multiplier, thisstep;
  142. float *buf = dz->sampbuf[0];
  143. if(is_log) {
  144. for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
  145. thisstep = ((double)i/(double)incr_cnt) * step;
  146. thisstep = pow(10,thisstep);
  147. multiplier = startval * thisstep;
  148. for(chanpos=0; chanpos < chans; chanpos++) {
  149. bufpos = startsamp + offset + chanpos;
  150. newval = (double)(buf[bufpos] * multiplier);
  151. newval = min(newval,(double)F_MAXSAMP);
  152. newval = max(newval,(double)F_MINSAMP);
  153. buf[bufpos] = (float) /*round*/(newval);
  154. }
  155. }
  156. } else {
  157. for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
  158. for(chanpos=0; chanpos < chans; chanpos++) {
  159. bufpos = startsamp + offset + chanpos;
  160. newval = (double)buf[bufpos] * (startval + (step * (double)i));
  161. newval = min(newval,(double)F_MAXSAMP);
  162. newval = max(newval,(double)F_MINSAMP);
  163. buf[bufpos] = (float) /*round*/(newval);
  164. }
  165. }
  166. }
  167. }
  168. /****************************** STEP_GEN ******************************
  169. *
  170. * Generates [stereo]-sample-wise step, for each window.
  171. */
  172. #define STEP_LINEAR_LIMIT (1.0)
  173. void step_gen(float *thisval,float *nextval,double *step,float **envptr,int *is_log,int incr_cnt)
  174. {
  175. double valstep, absstep;
  176. *thisval = *nextval;
  177. (*envptr)++;
  178. *nextval = **envptr;
  179. valstep = *nextval - *thisval;
  180. *step = valstep/(double)incr_cnt;
  181. /* LOG INTERP FOR EXTREME CASES ONLY --> */
  182. if((absstep = fabs(*step)) > STEP_LINEAR_LIMIT) {
  183. *step = log10((*nextval)/(*thisval));
  184. *is_log = TRUE;
  185. }
  186. /* <-- LOG INTERP FOR EXTREME CASES ONLY */
  187. return;
  188. }
  189. /**************************** RESET_FILE_POS_AND_COUNTERS *************************/
  190. int reset_file_pos_and_counters(int fileno,dataptr dz)
  191. {
  192. if((sndseekEx(dz->ifd[fileno],0,0))<0) { /* reset all file pointers and counters */
  193. sprintf(errstr,"seek error: reset_file_pos_and_counters()\n");
  194. return(SYSTEM_ERROR);
  195. }
  196. dz->total_samps_read = 0;
  197. dz->samps_left = dz->insams[fileno];
  198. return(FINISHED);
  199. }
  200. /*************************** TEST_IMPOSE_ENVEL *************************
  201. *
  202. * WE Assume that buffersizes have been recalcd etc by this stage,
  203. * and that they were last-calculated for the CURRENT file!!
  204. *
  205. * envcnt MUST BE the TRUE length of the NEW envelope!!!
  206. */
  207. int test_impose_envel_on_sndfile(float *env,int envcnt,int bufcnt,int fileno,double *maxval,dataptr dz)
  208. {
  209. int exit_status;
  210. int n, cnt = 0;
  211. int envwindow_sampsize = dz->iparam[ENV_SAMP_WSIZE] ;
  212. int chans = dz->infile->channels;
  213. int incr_cnt = envwindow_sampsize/chans;
  214. float *envptr = env;
  215. double step = 0.0;
  216. float thisval = *envptr;
  217. float nextval = *envptr;
  218. if((exit_status = reset_file_pos_and_counters(fileno,dz))<0)
  219. return(exit_status);
  220. for(n = 0; n < bufcnt; n++) {
  221. if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
  222. return(exit_status);
  223. if(sloom)
  224. display_virtual_time(dz->total_samps_read,dz);
  225. test_apply_envel_to_buffer
  226. (dz->ssampsread,envwindow_sampsize,envcnt,&cnt,&envptr,&step,&thisval,&nextval,incr_cnt,chans,maxval,dz);
  227. }
  228. return(FINISHED);
  229. }
  230. /******************************* TEST_APPLY_ENVEL_TO_BUFFER [ENVAPPLY] ******************************/
  231. void test_apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,int *cnt,float **envptr,
  232. double *step,float *thisval,float *nextval,int incr_cnt,int chans,
  233. double *maxval,dataptr dz)
  234. {
  235. int is_log = FALSE;
  236. int startsamp = 0;
  237. while(samps_to_process >= envwindow_sampsize) {
  238. if(++(*cnt) < envcnt)
  239. step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
  240. else {
  241. *thisval = *nextval;
  242. *step = 0.0; /* retain last envelope value if we run out of values */
  243. is_log = FALSE;
  244. }
  245. test_apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,maxval,dz);
  246. startsamp += envwindow_sampsize;
  247. samps_to_process -= envwindow_sampsize;
  248. }
  249. if(samps_to_process) { /* Handle any final short buffer */
  250. if(++(*cnt) < envcnt)
  251. step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
  252. else {
  253. *thisval = *nextval;
  254. *step = 0.0; /* retain last envelope value if we run out of values */
  255. is_log = FALSE;
  256. }
  257. incr_cnt = samps_to_process/chans;
  258. test_apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,maxval,dz);
  259. }
  260. return;
  261. }
  262. /************************ TEST_APPLY_ENV_TO_WINDOW [DO_THE_ENV] ***********************/
  263. void test_apply_env_to_window
  264. (int incr_cnt,double step, float startval,
  265. int startsamp, int chans,int is_log,double *maxval,dataptr dz)
  266. {
  267. int i, offset, bufpos;
  268. int chanpos;
  269. double newval, multiplier, thisstep;
  270. float *buf = dz->sampbuf[0];
  271. if(is_log) {
  272. for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
  273. thisstep = ((double)i/(double)incr_cnt) * step;
  274. thisstep = pow(10,thisstep);
  275. multiplier = startval * thisstep;
  276. for(chanpos=0; chanpos < chans; chanpos++) {
  277. bufpos = startsamp + offset + chanpos;
  278. newval = (double)(buf[bufpos] * multiplier);
  279. *maxval = max(*maxval,fabs(newval));
  280. }
  281. }
  282. } else {
  283. for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
  284. for(chanpos=0; chanpos < chans; chanpos++) {
  285. bufpos = startsamp + offset + chanpos;
  286. newval = (double)buf[bufpos] * (startval + (step * (double)i));
  287. *maxval = max(*maxval,fabs(newval));
  288. }
  289. }
  290. }
  291. }
  292. /************************ ADJUST_ENVELOPE ***********************/
  293. void adjust_envelope(double adjuster,int envcnt,dataptr dz)
  294. {
  295. float *envptr = dz->env;
  296. float *envend = envptr + envcnt;
  297. while(envptr < envend) {
  298. *envptr = (float)(*envptr * adjuster);
  299. envptr++;
  300. }
  301. }