abfpan.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. //abfpan.cpp : write mono wave file into ambisonic B-format
  21. // Dec 2005 support .amb extension, and 3ch output
  22. // Jan 2010: corrected usage message about -b and -x
  23. // Nov 2013: updated usage message formatting, infile must be mono
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <math.h>
  28. #include "portsf.h"
  29. #ifdef unix
  30. /* in portsf.lib */
  31. extern "C" {
  32. int stricmp(const char *a, const char *b);
  33. }
  34. #endif
  35. #ifndef TWOPI
  36. #define TWOPI (6.283185307)
  37. #endif
  38. typedef struct abf_samp {
  39. float W;
  40. float X;
  41. float Y;
  42. float Z;
  43. } ABFSAMPLE;
  44. enum {ARG_PROGNAME, ARG_INFILE, ARG_OUTFILE,ARG_STARTPOS, ARG_ENDPOS,ARG_NARGS};
  45. void usage()
  46. {
  47. fprintf(stderr,"CDP MCTOOLS V1.5.3 (c) RWD,CDP 2009,2010,2013\n"
  48. "ABFPAN: apply fixed or orbiting 1st-order B-Format pan to infile\n");
  49. fprintf(stderr,"usage : abfpan [-b][-x][-oN] infile outfile startpos endpos\n");
  50. fprintf(stderr," infile: input soundfile, must be mono\n");
  51. fprintf(stderr," startpos: 0.0 <= startpos <= 1.0 (0.0 and 1.0 = Centre Front)\n");
  52. fprintf(stderr," endpos: endpos < 0.0 gives anticlockwise rotation,\n"
  53. " endpos > 0.0 gives clockwise rotation.\n"
  54. " Units give number of revolutions, fraction gives final position\n"
  55. " Set endpos = startpos for fixed pan\n");
  56. fprintf(stderr," -b: write output as horizontal Ambisonic B-format (.amb),\n"
  57. " (i.e. bypass B-Format decoding).\n"
  58. " -x: write (WAVE_EX) format file (.wav). \n"
  59. " Default: write standard m/c soundfile (WAVE,AIFF).\n"
  60. " NB: -b overrides -x - no meaning in using both.\n"
  61. " -oN: number of B-Format output channels: N = 3 or 4 only.\n"
  62. " Default: write 4-ch file.\n"
  63. " See also ABFPAN2 for 2nd order version with fixed height.\n"
  64. );
  65. fprintf(stderr,"\n");
  66. }
  67. #define SYN_BUFLEN (32768)
  68. #define TABLEN (1024)
  69. int main(int argc,char *argv[])
  70. {
  71. int ifd, ofd;
  72. int srate = 44100;
  73. int outchans = 4;
  74. MYLONG peaktime;
  75. long outsize;
  76. float this_samp;
  77. char *sfname;
  78. double angle_incr;
  79. double start_angle = 0.0;
  80. double startpos,endpos;
  81. ABFSAMPLE abfsample;
  82. PSF_PROPS props;
  83. PSF_CHPEAK peaks[4];
  84. bool write_bformat = false;
  85. bool write_wavex = false;
  86. int iarg = outchans;
  87. /* CDP version number */
  88. if(argc==2 && (stricmp(argv[1],"--version")==0)){
  89. printf("1.5.2.\n");
  90. return 0;
  91. }
  92. if(argc < 5){
  93. usage();
  94. return 1;
  95. }
  96. if(psf_init()){
  97. fprintf(stderr,"abfpan2: Startup failure.\n");
  98. return 1;
  99. }
  100. while(argv[1][0] =='-'){
  101. switch(argv[1][1]){
  102. case('b'):
  103. write_bformat = true;
  104. break;
  105. case('x'):
  106. write_wavex = true;
  107. break;
  108. case('o'):
  109. if(argv[1][2]=='\0'){
  110. fprintf(stderr,"abfpan: error: -o flag requires channel value\n");
  111. return 1;
  112. }
  113. iarg = atoi(&(argv[1][2]));
  114. if(!(iarg == 3 || iarg == 4)){
  115. fprintf(stderr,"abfpan: error: invalid channel value for -o flag\n");
  116. return 1;
  117. }
  118. break;
  119. default:
  120. fprintf(stderr,"abfpan: error: illegal flag option %s.\n",argv[1]);
  121. return 1;
  122. }
  123. argc--; argv++;
  124. }
  125. if(argc != 5){
  126. usage();
  127. return 1;
  128. }
  129. if(write_bformat)
  130. outchans = iarg;
  131. sfname = argv[ARG_INFILE];
  132. startpos = atof(argv[ARG_STARTPOS]);
  133. if(startpos < 0.0 || startpos > 1.0){
  134. fprintf(stderr,"abfpan: startpos %.4lf out of range: must be between 0.0 and 1.0.\n",startpos);
  135. return 1;
  136. }
  137. endpos = atof(argv[ARG_ENDPOS]);
  138. ifd = psf_sndOpen(sfname,&props,0);
  139. if(ifd < 0){
  140. fprintf(stderr,"abfpan: unable to open infile %s.\n",argv[1]);
  141. return 1;
  142. }
  143. if(props.chans != 1){
  144. fprintf(stderr,"abfpan: infile must be mono.\n");
  145. psf_sndClose(ifd);
  146. return 1;
  147. }
  148. outsize = psf_sndSize(ifd);
  149. if(outsize <= 0){
  150. fprintf(stderr,"abfpan: infile is empty!\n");
  151. psf_sndClose(ifd);
  152. return 1;
  153. }
  154. srate = props.srate;
  155. props.chans = outchans;
  156. if(!is_legalsize(outsize,&props)){
  157. fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
  158. return 1;
  159. }
  160. start_angle = - (TWOPI * startpos); //we think of positive as clockwise at cmdline!
  161. angle_incr = TWOPI / outsize;
  162. angle_incr *= (endpos - startpos);
  163. if(write_wavex){
  164. props.format = PSF_WAVE_EX;
  165. props.chformat = MC_QUAD;
  166. }
  167. if(write_bformat)
  168. props.chformat = MC_BFMT;
  169. ofd = psf_sndCreate(argv[ARG_OUTFILE],&props,0,0,PSF_CREATE_RDWR);
  170. if(ofd < 0){
  171. fprintf(stderr,"abfpan: can't create outfile %s.\n",argv[ARG_OUTFILE]);
  172. return 1;
  173. }
  174. int i,got;
  175. int half_sec = srate / 4;
  176. long total_frames = 0;
  177. double d_srate = (double)srate;
  178. abfsample.Z = 0.0f;
  179. for(i=0; i < outchans; i++){
  180. peaks[i].val = 0.0f;
  181. peaks[i].pos = 0;
  182. }
  183. //should make one 360deg rotate over duration
  184. //TODO: make lookup_sin and lookup_cos ugens, taking angle arg
  185. if(write_bformat)
  186. printf("\nWriting B-Format file:\n");
  187. else
  188. printf("\n");
  189. while((got = psf_sndReadFloatFrames(ifd,&this_samp,1))==1){
  190. abfsample.W = (float) (this_samp * 0.707);
  191. abfsample.X = (float) (this_samp * cos(start_angle));
  192. abfsample.Y = (float) (this_samp * sin(start_angle));
  193. //set this for periphonic; otherwise = 0.0 for horizontal_only
  194. //abfsample.Z = (float) (this_samp*0.25);
  195. if(!write_bformat){
  196. //decode into quad file
  197. float aw = abfsample.W;
  198. float ax = abfsample.X * 0.707f;
  199. float ay = abfsample.Y * 0.707f;
  200. /* ignore wxyz names - this is now handy container for quad speaker feeds*/
  201. abfsample.W = 0.33333f * (aw + ax + ay); /* front L */
  202. abfsample.X = 0.33333f * (aw + ax - ay); /* front R */
  203. abfsample.Y = 0.33333f * (aw - ax + ay); /* rear L */
  204. abfsample.Z = 0.33333f * (aw - ax - ay); /* rear R */
  205. }
  206. if(0 > psf_sndWriteFloatFrames(ofd,(float*) &abfsample,1)){
  207. fprintf(stderr,"error writing abf sample frame %ld\n",total_frames);
  208. return 1;
  209. }
  210. start_angle -= angle_incr;
  211. total_frames++;
  212. if(total_frames % half_sec ==0) {
  213. printf("%.2lf secs\r",(double)total_frames / d_srate);
  214. fflush(stdout);
  215. }
  216. }
  217. if(got != 0){
  218. fprintf(stderr,"abfpan: warning: not all data was read.\n");
  219. }
  220. printf("%.4lf secs\nwritten %ld %d-ch sample frames to %s\n",(double)outsize / d_srate,outsize,outchans, argv[ARG_OUTFILE]);
  221. if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
  222. printf("PEAK values:\n");
  223. for(i=0; i < outchans; i++){
  224. double val, dbval;
  225. val = (double) peaks[i].val;
  226. if(val > 0.0){
  227. dbval = 20.0 * log10(val);
  228. printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
  229. val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props.srate);
  230. }
  231. else{
  232. printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
  233. val, (unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props.srate);
  234. }
  235. }
  236. }
  237. printf("\n");
  238. psf_sndClose(ifd);
  239. psf_sndClose(ofd);
  240. psf_finish();
  241. return 0;
  242. }