nmix.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
  3. * http://people.bath.ac.uk/masrwd
  4. * http://www.composersdesktop.com
  5. * This file is part of the CDP System.
  6. * The CDP System is free software; you can redistribute it
  7. * and/or modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  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.
  14. * See the 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 02111-1307 USA
  18. *
  19. */
  20. //nmix.c
  21. //Oct 2009 updated to use portsf
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <math.h>
  26. #include <memory.h>
  27. #include <sys/timeb.h>
  28. #include "portsf.h"
  29. #ifdef unix
  30. /* in portsf.lib */
  31. extern int stricmp(const char *a, const char *b);
  32. #endif
  33. //usage: nmix [-oOFFSET] [-f] infile1 infile2 outfile
  34. void usage() {
  35. printf("\nCDP MCTOOLS: NMIX V2.0.1 (c) RWD,CDP 1999,2009\n"
  36. "mix two multi-channel files\n"
  37. "usage:\n"
  38. "nmix [-d][-f][-oOFFSET] infile1 infile2 outfile\n"
  39. " -d : apply TPDF dither (16bit format output only).\n"
  40. " -f : set output sample type to floats.\n"
  41. " Default: outfile type is that of infile 1\n"
  42. " -oOFFSET: start infile2 at OFFSET seconds.\n"
  43. "Files must have the same channel count.\n"
  44. "WAVE-EX files must have the same speaker layout\n");
  45. exit(0);
  46. }
  47. #define BUFLEN (1024)
  48. int main(int argc, char *argv[])
  49. {
  50. int i,ifd1 = -1,ifd2=-1,ofd=-1;
  51. int force_floats = 0;
  52. int do_dither = 0;
  53. float ampfac = 0.0;
  54. long len_in1, len_in2,outlen;
  55. double offset = 0.0;
  56. long offsetframes = 0,framecount = 0;
  57. long chans;
  58. long sr;
  59. long in1_sofar,in2_sofar;
  60. int halfsec;
  61. MYLONG peaktime;
  62. PSF_PROPS props_in1,props_in2;
  63. float *frame_in1 = NULL, *frame_in2 = NULL, *outframe = NULL;
  64. PSF_CHPEAK *peaks = NULL;
  65. /* CDP version number */
  66. if(argc==2 && (stricmp(argv[1],"--version")==0)){
  67. printf("2.0.1\n");
  68. return 0;
  69. }
  70. if(argc < 4)
  71. usage();
  72. while(argv[1][0]=='-'){
  73. char *valstr;
  74. double val;
  75. switch(argv[1][1]){
  76. case 'd':
  77. do_dither = 1;
  78. break;
  79. case('f'):
  80. force_floats = 1;
  81. break;
  82. case('o'):
  83. if(argv[1][2]=='\0'){
  84. fprintf(stderr,"-o flag needs a number\n");
  85. exit(1);
  86. }
  87. valstr = &argv[1][2];
  88. val=atof(valstr);
  89. if(val < 0.0){
  90. fprintf(stderr,"offset must be >= 0\n");
  91. exit(1);
  92. }
  93. if(val > 0.0)
  94. offset = val;
  95. break;
  96. default:
  97. fprintf(stderr,"incorrect flag option %c\n",argv[1][1]);
  98. exit(1);
  99. }
  100. argc--; argv++;
  101. }
  102. if(argc < 4)
  103. usage();
  104. if(force_floats && do_dither)
  105. fprintf(stderr,"Warning: dither option ignored for floats format.\n");
  106. psf_init();
  107. //open soundfiles: no auto-rescaling
  108. if((ifd1 = psf_sndOpen(argv[1],&props_in1,0)) < 0){
  109. fprintf(stderr,"Cannot open soundfile %s\n",argv[1]);
  110. goto cleanup;
  111. }
  112. if((ifd2 = psf_sndOpen(argv[2],&props_in2,0)) < 0){
  113. fprintf(stderr,"Cannot open soundfile %s \n",argv[2]);
  114. goto cleanup;
  115. }
  116. if(props_in1.chans != props_in2.chans){
  117. fprintf(stderr,"files do not have the same number of channels\n");
  118. goto cleanup;
  119. }
  120. if(props_in1.srate != props_in2.srate){
  121. fprintf(stderr,"files do not have the same sample rate\n");
  122. goto cleanup;
  123. }
  124. if(props_in1.chformat != props_in2.chformat){
  125. fprintf(stderr,"files do not have the same channel format\n");
  126. goto cleanup;
  127. }
  128. sr = props_in1.srate;
  129. chans = props_in1.chans;
  130. ampfac = 0.5f; //just mixing 2 files...
  131. if(offset > 0.0){
  132. offsetframes = (long) (offset * (double) sr);
  133. }
  134. /* now we can set up frame arrays */
  135. frame_in1 = (float *) calloc(chans, sizeof(float));
  136. frame_in2 = (float *) calloc(chans, sizeof(float));
  137. outframe = (float *) calloc(chans, sizeof(float));
  138. if(frame_in1==NULL || frame_in2==NULL || outframe==NULL ){
  139. puts("\nno memory for frame buffers");
  140. goto cleanup;
  141. }
  142. len_in1 = psf_sndSize(ifd1);
  143. if(len_in1==0){
  144. fprintf(stderr,"infile %s is empty!\n",argv[1]);
  145. goto cleanup;
  146. }
  147. len_in2 = psf_sndSize(ifd2);
  148. if(len_in2==0){
  149. fprintf(stderr,"infile %s is empty!\n",argv[2]);
  150. goto cleanup;
  151. }
  152. if(len_in1 < 0){
  153. fprintf(stderr,"system problem: cannot read size of infile %s\n",argv[1]);
  154. goto cleanup;
  155. }
  156. if(len_in2 < 0){
  157. fprintf(stderr,"system problem: cannot read size of infile %s\n",argv[2]);
  158. goto cleanup;
  159. }
  160. outlen = len_in2 + offsetframes;
  161. if(len_in1 > outlen)
  162. outlen = len_in1;
  163. #ifdef _DEBUG
  164. printf("DEBUG: outfile size expected to be %d frames\n",outlen);
  165. #endif
  166. //setup PEAK data
  167. peaks = (PSF_CHPEAK *) calloc(props_in1.chans,sizeof(PSF_CHPEAK));
  168. if(peaks==NULL){
  169. puts("nmix: error: no memory for internal PEAK buffer\n");
  170. goto cleanup;
  171. }
  172. if(force_floats)
  173. props_in1.samptype = PSF_SAMP_IEEE_FLOAT;
  174. if(!is_legalsize(outlen,&props_in1)){
  175. fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
  176. return 1;
  177. }
  178. if((ofd = psf_sndCreate(argv[3],&props_in1,0,0,PSF_CREATE_RDWR)) < 0){
  179. fprintf(stderr,"unable to create outfile %s\n",argv[3]);
  180. goto cleanup;
  181. }
  182. if(do_dither)
  183. psf_sndSetDither(ofd,PSF_DITHER_TPDF);
  184. halfsec = sr / 2;
  185. //OK now we can do it....
  186. printf("\nmixing....\n");
  187. in1_sofar = in2_sofar = 0;
  188. if(offsetframes > 0){
  189. for(i=0;i < offsetframes; i++){
  190. int got,j;
  191. got = psf_sndReadFloatFrames(ifd1,frame_in1,1);
  192. if(got != 1){
  193. fprintf(stderr,"error reading from infile 1\n");
  194. goto cleanup;
  195. }
  196. for(j=0;j < chans; j++) {
  197. frame_in1[j] *= ampfac;
  198. }
  199. if((psf_sndWriteFloatFrames(ofd,frame_in1,1)) !=1){
  200. fprintf(stderr,"\nerror writing to outfile\n");
  201. goto cleanup;
  202. }
  203. if(framecount % halfsec==0)
  204. printf("%.2lf secs\r",(double)framecount / (double) sr);
  205. framecount++;
  206. }
  207. }
  208. in1_sofar = offsetframes;
  209. //now we are mixing two files...
  210. for(i= offsetframes; i < outlen; i++){
  211. int got, j;
  212. //clear frame blocks
  213. memset(frame_in1,0, chans * sizeof(float));
  214. memset(frame_in2,0, chans * sizeof(float));
  215. //if we have data, fill frame and scale
  216. if(in1_sofar < len_in1){
  217. got = psf_sndReadFloatFrames(ifd1,frame_in1,1);
  218. if(got != 1){
  219. fprintf(stderr,"\nerror reading from infile 1\n");
  220. goto cleanup;
  221. }
  222. in1_sofar++;
  223. for(j=0;j < chans; j++)
  224. frame_in1[j] *= ampfac;
  225. }
  226. if(in2_sofar < len_in2){
  227. got = psf_sndReadFloatFrames(ifd2,frame_in2,1);
  228. if(got != 1){
  229. fprintf(stderr,"\nerror reading from infile 1\n");
  230. goto cleanup;
  231. }
  232. in2_sofar++;
  233. for(j=0;j < chans; j++)
  234. frame_in2[j] *= ampfac;
  235. }
  236. //mix and write
  237. for(j=0;j < chans; j++) {
  238. outframe[j] = frame_in1[j] + frame_in2[j];
  239. }
  240. if(psf_sndWriteFloatFrames(ofd,outframe,1) < 0){
  241. fprintf(stderr,"\nerror writing to outfile\n");
  242. goto cleanup;
  243. }
  244. if(framecount % halfsec==0) {
  245. printf("%.2lf secs\r",(double)framecount / (double) sr);
  246. fflush(stdout);
  247. }
  248. framecount++;
  249. }
  250. printf("%.4lf secs\nWritten %ld sample frames to %s\n",(double)framecount / (double)sr,framecount,argv[3]);
  251. if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
  252. printf("PEAK values:\n");
  253. for(i=0; i < chans; i++){
  254. double val, dbval;
  255. val = (double) peaks[i].val;
  256. if(val > 0.0){
  257. dbval = 20.0 * log10(val);
  258. printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
  259. val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props_in1.srate);
  260. }
  261. else{
  262. printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
  263. val,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props_in1.srate);
  264. }
  265. }
  266. }
  267. cleanup:
  268. if(ifd1 >=0)
  269. psf_sndClose(ifd1);
  270. if(ifd2 >=0)
  271. psf_sndClose(ifd2);
  272. if(ofd >=0)
  273. psf_sndClose(ofd);
  274. if(peaks)
  275. free(peaks);
  276. if(frame_in1 != NULL)
  277. free(frame_in1);
  278. if(frame_in2 != NULL)
  279. free(frame_in2);
  280. if(outframe != NULL)
  281. free(outframe);
  282. psf_finish();
  283. return 0;
  284. }