channels.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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 <cdpmain.h>
  28. #include <house.h>
  29. #include <modeno.h>
  30. #include <logic.h>
  31. #include <pnames.h>
  32. #include <flags.h>
  33. #include <sfsys.h>
  34. #include <string.h>
  35. /**
  36. #include <filetype.h>
  37. #include <limits.h>
  38. #include <math.h>
  39. **/
  40. /* mainfuncs.c */
  41. extern void dz2props(dataptr dz, SFPROPS* props);
  42. /*********************************** DO_CHANNELS ****************************/
  43. /* RWD NB changes to ensure outfile is created with correct chan count. */
  44. /* need full set of oufile props in dz, so we NEVER use dz-infile to spec the outfile! */
  45. /* TODO: support n_channels, e.g. for zero, channel etc */
  46. int do_channels(dataptr dz)
  47. {
  48. int exit_status;
  49. int chans = dz->infile->channels, start_chan = 0, end_chan = 0;
  50. double maxoutsum, maxinval, sum, normaliser = 0.0;
  51. //TW REVISION Dec 2002
  52. // char *outfilename, *outfilenumber;
  53. char *outfilename;
  54. char prefix[] = "_c";
  55. int namelen;
  56. int prefixlen = strlen(prefix);
  57. int infilesize, outfilesize;
  58. int k, m, n, j;
  59. float *buf = dz->bigbuf;
  60. int not_zeroed = 0, zeroed = 0, totlen;
  61. switch(dz->mode) {
  62. case(HOUSE_CHANNEL):
  63. dz->iparam[CHAN_NO]--; /* change to internal numbering */
  64. break;
  65. case(HOUSE_ZCHANNEL):
  66. dz->iparam[CHAN_NO]--; /* change to internal numbering */
  67. zeroed = dz->iparam[CHAN_NO];
  68. not_zeroed = !dz->iparam[CHAN_NO];
  69. break;
  70. }
  71. switch(dz->mode) {
  72. case(HOUSE_CHANNEL):
  73. case(HOUSE_CHANNELS):
  74. dz->buflen *= chans; /* read chan * (contiguous) buffers */
  75. // FEB 2010 TW
  76. // if(!sloom) {
  77. // namelen = strlen(dz->wordstor[0]);
  78. // q = dz->wordstor[0];
  79. // r = dz->wordstor[0] + namelen;
  80. // p = r - 1;
  81. // while((*p != '\\') && (*p != '/') && (*p != ':')) {
  82. // p-- ;
  83. // if(p < dz->wordstor[0])
  84. // break;
  85. // }
  86. // if(p > dz->wordstor[0]) {
  87. // p++;
  88. // while(p <= r)
  89. // *q++ = *p++;
  90. // }
  91. // }
  92. namelen = strlen(dz->wordstor[0]);
  93. if(!sloom)
  94. // FEB 2010 TW
  95. totlen = namelen + prefixlen + 20;
  96. else
  97. // FEB 2010 TW
  98. totlen = namelen + 20;
  99. if((outfilename = (char *)malloc(totlen * sizeof(char)))==NULL) {
  100. sprintf(errstr,"INSUFFICIENT MEMORY for outfile name.\n");
  101. return(MEMORY_ERROR);
  102. }
  103. switch(dz->mode) {
  104. case(HOUSE_CHANNEL):
  105. dz->tempsize = dz->insams[0]/chans; /* total outfile size */
  106. start_chan = dz->iparam[CHAN_NO];
  107. end_chan = dz->iparam[CHAN_NO]+1;
  108. break;
  109. case(HOUSE_CHANNELS):
  110. dz->tempsize = dz->insams[0]/dz->infile->channels;
  111. start_chan = 0;
  112. end_chan = dz->infile->channels;
  113. break;
  114. }
  115. dz->process_type = EQUAL_SNDFILE; /* allow sndfile(s) to be created */
  116. /*RWD: GRRR! */
  117. dz->infile->channels = MONO; /* force outfile(s) to be mono */
  118. infilesize = dz->insams[0];
  119. outfilesize = dz->insams[0]/chans;
  120. for(k=start_chan,j=0;k<end_chan;k++,j++) {
  121. if(sndseekEx(dz->ifd[0],0,0)<0) {
  122. sprintf(errstr,"sndseek failed.\n");
  123. return(SYSTEM_ERROR);
  124. }
  125. dz->total_samps_written = 0;
  126. dz->samps_left = dz->insams[0];
  127. dz->total_samps_read = 0; /* NB total_samps_read NOT reset */
  128. strcpy(outfilename,dz->wordstor[0]);
  129. if(!sloom) {
  130. insert_new_chars_at_filename_end(outfilename,prefix);
  131. insert_new_number_at_filename_end(outfilename,k+1,0);
  132. } else
  133. insert_new_number_at_filename_end(outfilename,j,1);
  134. dz->insams[0] = outfilesize; /* creates smaller outfile */
  135. if((exit_status = create_sized_outfile(outfilename,dz))<0) {
  136. sprintf(errstr,"Cannot open output file %s\n", outfilename);
  137. dz->insams[0] = infilesize;
  138. free(outfilename);
  139. return(DATA_ERROR);
  140. }
  141. dz->insams[0] = infilesize; /* restore true value */
  142. while(dz->samps_left) {
  143. if((exit_status = read_samps(buf,dz))<0) {
  144. free(outfilename);
  145. return(exit_status);
  146. }
  147. for(n=k,m=0;n<dz->ssampsread;n+=chans,m++)
  148. buf[m] = buf[n];
  149. if(dz->ssampsread > 0) {
  150. if((exit_status = write_exact_samps(buf,dz->ssampsread/chans,dz))<0) {
  151. free(outfilename);
  152. return(exit_status);
  153. }
  154. }
  155. }
  156. dz->outfiletype = SNDFILE_OUT; /* allows header to be written */
  157. /* RWD: will eliminate this eventually */
  158. if((exit_status = headwrite(dz->ofd,dz))<0) {
  159. free(outfilename);
  160. return(exit_status);
  161. }
  162. if(k < end_chan - 1) {
  163. if((exit_status = reset_peak_finder(dz))<0)
  164. return(exit_status);
  165. if(sndcloseEx(dz->ofd) < 0) {
  166. fprintf(stdout,"WARNING: Can't close output soundfile %s\n",outfilename);
  167. fflush(stdout);
  168. }
  169. /*free(outfilename);*/ /*RWD 25:9:2001 used again! */
  170. dz->ofd = -1;
  171. }
  172. }
  173. break;
  174. case(HOUSE_ZCHANNEL):
  175. case(STOM):
  176. case(MTOS):
  177. switch(chans) {
  178. case(MONO):
  179. switch(dz->mode) {
  180. case(HOUSE_ZCHANNEL):
  181. /*RWD*/
  182. dz->outfile->channels = 2;
  183. dz->tempsize = dz->insams[0] * 2; break; /* total output size */
  184. case(STOM):
  185. sprintf(errstr,"This file is already mono!!\n"); return(GOAL_FAILED);
  186. case(MTOS):
  187. /*RWD*/
  188. dz->outfile->channels = 2;
  189. dz->tempsize = dz->insams[0] * 2; break; /* total output size */
  190. }
  191. break;
  192. case(STEREO):
  193. dz->buflen *= chans; /* read chans * (contiguous) buffers */
  194. switch(dz->mode) {
  195. case(HOUSE_ZCHANNEL):
  196. /*RWD*/
  197. dz->outfile->channels = 2;
  198. dz->tempsize = dz->insams[0]; break; /* total output size */
  199. case(STOM):
  200. /*RWD*/
  201. dz->outfile->channels = 1;
  202. dz->tempsize = dz->insams[0]/2; break; /* total output size */
  203. case(MTOS): sprintf(errstr,"This file is already stereo!!\n"); return(GOAL_FAILED);
  204. }
  205. break;
  206. default:
  207. switch(dz->mode) {
  208. case(MTOS):
  209. sprintf(errstr,"This process does not work with multichannel files!!\n"); return(GOAL_FAILED);
  210. break;
  211. case(STOM): // MULTICHAN APPLICATION FOR MAKING THUMBNAILS
  212. dz->buflen *= chans; /* read chans * (contiguous) buffers */
  213. dz->outfile->channels = 1;
  214. break;
  215. case(HOUSE_ZCHANNEL):
  216. dz->buflen *= chans; /* read chans * (contiguous) buffers */
  217. dz->outfile->channels = dz->infile->channels;
  218. break;
  219. }
  220. break;
  221. }
  222. /*RWD NOW, we can create the outfile! */
  223. /*RWD April 2005 need this for wave-ex */
  224. if(dz->outfile->channels > 2 || dz->infile->stype > SAMP_FLOAT){
  225. SFPROPS props, inprops;
  226. dz2props(dz,&props);
  227. props.chans = dz->outfile->channels;
  228. props.srate = dz->infile->srate;
  229. /* RWD: always need to hack it one way or another!*/
  230. if(dz->ifd && dz->ifd[0] >=0) {
  231. if(snd_headread(dz->ifd[0], &inprops)){
  232. /* if we receive an old WAVE 24bit file, want to write new wave-ex one! */
  233. if(inprops.chformat == STDWAVE)
  234. props.chformat = MC_STD;
  235. else
  236. props.chformat = inprops.chformat;
  237. }
  238. }
  239. #ifdef _DEBUG
  240. printf("DEBUG: writing WAVE_EX outfile\n");
  241. #endif
  242. dz->ofd = sndcreat_ex(dz->outfilename,-1,&props,SFILE_CDP,CDP_CREATE_NORMAL);
  243. if(dz->ofd < 0){
  244. sprintf(errstr,"Cannot open output file %s : %s\n", dz->outfilename,sferrstr());
  245. return(DATA_ERROR);
  246. }
  247. }
  248. else
  249. //create outfile here, now we have required format info
  250. dz->ofd = sndcreat_formatted(dz->outfilename,-1,dz->infile->stype,dz->outfile->channels,
  251. dz->infile->srate,
  252. CDP_CREATE_NORMAL);
  253. //TW ADDED, for peak chunk
  254. dz->outchans = dz->outfile->channels;
  255. establish_peak_status(dz);
  256. if(dz->ofd < 0)
  257. return DATA_ERROR;
  258. // MULTICHAN APPLICATION FOR MAKING THUMBNAILS -->
  259. if(dz->mode == STOM && chans > 2) {
  260. maxoutsum = 0.0;
  261. maxinval = 0.0;
  262. while(dz->samps_left) {
  263. if((exit_status = read_samps(buf,dz))<0) {
  264. return(exit_status);
  265. }
  266. for(n=0;n< dz->ssampsread;n+=chans) {
  267. sum = 0.0;
  268. for(m=0;m < chans;m++) {
  269. maxinval = max(maxinval,fabs(buf[n+m]));
  270. sum += buf[n+m];
  271. }
  272. maxoutsum = max(maxoutsum,fabs(sum));
  273. }
  274. }
  275. normaliser = maxinval/maxoutsum;
  276. sndseekEx(dz->ifd[0],0,0);
  277. reset_filedata_counters(dz);
  278. }
  279. // <-- MULTICHAN APPLICATION FOR MAKING THUMBNAILS
  280. while(dz->samps_left) {
  281. if((exit_status = read_samps(buf,dz))<0) {
  282. return(exit_status);
  283. }
  284. if(dz->ssampsread > 0) {
  285. switch(chans) {
  286. case(MONO):
  287. switch(dz->mode) {
  288. case(HOUSE_ZCHANNEL):
  289. for(n=dz->ssampsread-MONO,m=(dz->ssampsread*STEREO)-STEREO;n>=0;n--,m-=2) {
  290. buf[m+zeroed] = (float)0;
  291. buf[m+not_zeroed] = buf[n];
  292. }
  293. if((exit_status = write_samps(buf,dz->ssampsread * STEREO,dz))<0)
  294. return(exit_status);
  295. break;
  296. case(MTOS):
  297. for(n=dz->ssampsread-MONO,m=(dz->ssampsread*STEREO)-STEREO,k=m+1;n>=0;n--,m-=2,k-=2) {
  298. buf[m] = buf[n];
  299. buf[k] = buf[n];
  300. }
  301. if((exit_status = write_samps(buf,dz->ssampsread * STEREO,dz))<0)
  302. return(exit_status);
  303. break;
  304. }
  305. break;
  306. case(STEREO):
  307. switch(dz->mode) {
  308. case(HOUSE_ZCHANNEL):
  309. for(n=dz->iparam[CHAN_NO];n< dz->ssampsread;n+=2)
  310. buf[n] = (float)0;
  311. if((exit_status = write_samps(buf,dz->ssampsread,dz))<0) {
  312. return(exit_status);
  313. }
  314. break;
  315. case(STOM):
  316. if(dz->vflag[CHAN_INVERT_PHASE]) {
  317. for(n=0,m=0;n< dz->ssampsread;n+=2,m++)
  318. buf[m] = (float)((buf[n] - buf[n+1])/2.0);
  319. } else {
  320. for(n=0,m=0;n< dz->ssampsread;n+=2,m++)
  321. buf[m] = (float)((buf[n] + buf[n+1])/2.0);
  322. }
  323. if((exit_status = write_samps(buf,dz->ssampsread/2,dz))<0) {
  324. return(exit_status);
  325. }
  326. break;
  327. }
  328. break;
  329. default: // HOUSE_ZCHANNEL
  330. switch(dz->mode) {
  331. case(HOUSE_ZCHANNEL):
  332. for(n=dz->iparam[CHAN_NO];n< dz->ssampsread;n+=dz->infile->channels)
  333. buf[n] = (float)0;
  334. if((exit_status = write_samps(buf,dz->ssampsread,dz))<0) {
  335. return(exit_status);
  336. }
  337. break;
  338. case(STOM): // MULTICHAN APPLICATION FOR MAKING THUMBNAILS
  339. for(n=0,m=0;n< dz->ssampsread;n+=chans,m++) {
  340. sum = 0.0;
  341. for(k=0;k < chans;k++)
  342. sum += buf[n+k];
  343. sum *= normaliser;
  344. buf[m] = (float)sum;
  345. }
  346. if((exit_status = write_samps(buf,dz->ssampsread/chans,dz))<0) {
  347. return(exit_status);
  348. }
  349. break;
  350. }
  351. break;
  352. }
  353. }
  354. }
  355. switch(dz->mode) {
  356. case(HOUSE_ZCHANNEL): dz->infile->channels = dz->outfile->channels; break;
  357. case(STOM): dz->infile->channels = MONO; break;
  358. case(MTOS): dz->infile->channels = STEREO; break;
  359. }
  360. break;
  361. }
  362. return(FINISHED);
  363. }