channel.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. /* channelx.c */
  21. //RWD MCTOOLS, portsf version Oct 2009
  22. // nothing special, but use PEAK chunk (reading it where available)
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <math.h>
  27. #include <memory.h>
  28. #include <ctype.h>
  29. #include <portsf.h>
  30. #ifndef _MAX_PATH
  31. #define _MAX_PATH (1024)
  32. #endif
  33. #define MAXFILES 16
  34. #ifdef unix
  35. /* in portsf.lib */
  36. extern int stricmp(const char *a, const char *b);
  37. #endif
  38. void usage(void);
  39. //RWD.7.99 extended to get file extension from base name
  40. // so can be used without CDP_SOUND_EXT
  41. static void getbody(char*,char*,char *);
  42. void
  43. usage(void)
  44. {
  45. fprintf(stderr,"\nCDP MCTOOLS: CHANNELX V1.6 (c) RWD, CDP 2010\n");
  46. fprintf(stderr,
  47. "Extract all channels from m/c file\n"
  48. "usage: channelx [-oBASENAME] infile chan_no [chan_no...]\n"
  49. //"\nusage: channelx [-oBASENAME] infile"
  50. " -oBASENAME = base name (with extension) of outfiles (appended *_cN for ch N)\n"
  51. "(NB: Channels of WAVE-EX files are written as standard soundfiles)\n"
  52. );
  53. }
  54. #if defined(unix)
  55. #define SEP '/'
  56. #else
  57. #define SEP '\\'
  58. #endif
  59. void getbody(char *filename,char *body,char *ext)
  60. {
  61. char *fn, *sl;
  62. if((sl = strrchr(filename, SEP)) != 0)
  63. sl++;
  64. else
  65. sl = filename;
  66. for(fn = sl; *fn != '.' && *fn != '\0'; ) {
  67. *body++ = *fn++;
  68. }
  69. *body++ = '\0';
  70. //save extension
  71. while(*fn != '\0')
  72. *ext++ = *fn++;
  73. *ext = '\0';
  74. }
  75. int main(int argc,char *argv[])
  76. {
  77. int ifd = 0; /* Infile descriptor */
  78. int ofd[MAXFILES]; /* Outfile descriptors */
  79. int i; /* Assorted indexes */
  80. int inchans=1; /* Infile channels */
  81. char filename[_MAX_PATH]; /* Infilename */
  82. int select[MAXFILES]; /* Flags for each channel to MAXFILES */
  83. int lastchan = 0; /* Maximum Requested channels */
  84. int numchans = 0; /* number of channels extracted */
  85. char body[100]; /* Infile name prefix */
  86. char ext[8];
  87. char outext[8]; /* output extension: to change .amb to .wav */
  88. char *p_dot;
  89. char ofile[_MAX_PATH]; /* Raw outfile name */
  90. PSF_PROPS inprops;
  91. int nframes =0, total_frames = 0;
  92. float *frame = NULL;
  93. int writefiles = 0; /* try to keep working even if one file fails...*/
  94. /* CDP version number */
  95. if(argc==2 && (stricmp(argv[1],"--version")==0)){
  96. printf("1.6.\n");
  97. return 0;
  98. }
  99. if(argc<2) {
  100. usage();
  101. return 1;
  102. }
  103. if(psf_init()) {
  104. fprintf(stderr,"Startup failure.\n");
  105. return 1;
  106. }
  107. body[0] = '\0';
  108. ext[0] = '\0';
  109. while(argv[1] != 0 && argv[1][0] == '-') {
  110. if(strncmp(argv[1], "-o", 2) == 0) {
  111. if(body[0] != '\0')
  112. usage();
  113. strcpy(body, &argv[1][2]);
  114. }
  115. argv++;
  116. argc--;
  117. }
  118. if(argc < 2) {
  119. usage();
  120. return 1;
  121. }
  122. if(argv[1] != 0) {
  123. sprintf(filename,"%s",argv[1]);
  124. if((ifd = psf_sndOpen(filename,&inprops,0)) < 0) {
  125. fprintf(stderr,"Channelx: Cannot open input file %s\n",argv[1]);
  126. return 1;
  127. }
  128. }
  129. argv++;
  130. if(inprops.chans > MAXFILES){
  131. fprintf(stderr,"Channelx: infile has too many channels!\n");
  132. psf_sndClose(ifd);
  133. return 1;
  134. }
  135. inchans = inprops.chans;
  136. nframes = psf_sndSize(ifd);
  137. if(nframes < 0){
  138. fprintf(stderr,"Channelx: error reading infile size\n");
  139. psf_sndClose(ifd);
  140. return 1;
  141. }
  142. if(nframes==0){
  143. fprintf(stderr,"Channelx: infile contains no data!\n");
  144. psf_sndClose(ifd);
  145. return 1;
  146. }
  147. nframes /= inchans;
  148. //always create a standard file!
  149. if(inprops.format == PSF_WAVE_EX) {
  150. inprops.format = PSF_STDWAVE;
  151. inprops.chformat = STDWAVE;
  152. }
  153. //that's all we need to know, now set one output channel
  154. inprops.chans = 1;
  155. frame = calloc(inchans,sizeof(float));
  156. if(frame == NULL){
  157. puts("Channelx: no memory for internal sample data\n");
  158. psf_sndClose(ifd);
  159. return 1;
  160. }
  161. for(i=0;i<MAXFILES;i++){
  162. select[i] = 0;
  163. ofd[i] = -1;
  164. }
  165. while(argv[1] != 0) {
  166. int chn;
  167. if(sscanf(argv[1],"%d",&chn) < 1){
  168. fprintf(stderr,
  169. "Channelx: illegal channel argument %s\n\n",argv[1]);
  170. goto cleanup;
  171. }
  172. if((chn > inchans) || (chn < 1)){
  173. fprintf(stderr,"Channelx: channel argument out of range\n\n");
  174. goto cleanup;
  175. }
  176. //check for duplicates
  177. if(select[chn-1]==0){
  178. select[chn-1] = 1;
  179. if(chn > lastchan)
  180. lastchan = chn;
  181. numchans++;
  182. }
  183. else
  184. fprintf(stderr,"Channelx: WARNING: duplicate channel number %d\n",chn);
  185. argv++;
  186. argc--;
  187. }
  188. if(numchans < 1) { //RWD
  189. fprintf(stderr, "channelx: must extract at least one channel\n");
  190. goto cleanup;
  191. }
  192. writefiles = numchans;
  193. if(body[0] == '\0')
  194. getbody(filename,body,ext);
  195. else if((p_dot = strrchr(body,'.')) != NULL){
  196. //extension set in body arg
  197. *p_dot++ = '\0';
  198. sprintf(ext,".%s",p_dot);
  199. }
  200. //trap ambisonic file; single channels must be wav
  201. strcpy(outext,ext);
  202. if(stricmp(outext,".amb")==0)
  203. strcpy(outext,".wav");
  204. for(i=0;i<inchans;i++){
  205. if(select[i]){
  206. sprintf(ofile, "%s_c%d%s", body, i+1,outext);
  207. if((ofd[i] = psf_sndCreate(ofile,&inprops,0,0,PSF_CREATE_RDWR)) < 0) {
  208. fprintf(stderr,"Channelx: Failed to create %s\n\n",ofile);
  209. goto cleanup;
  210. }
  211. }
  212. }
  213. printf("Extracting %d channels from '%s':\n%d sample frames\n",numchans,filename,nframes);
  214. //stopwatch(1);
  215. for(i=0;i < nframes; i++){
  216. int got;
  217. if(writefiles==0)
  218. goto cleanup;
  219. if((got = psf_sndReadFloatFrames(ifd,frame,1)) < 1){
  220. if(got < 0)
  221. fprintf(stderr,"error reading data from infile, after %d frames\n",i);
  222. //sndunlink all outfiles?
  223. else
  224. break;
  225. //goto cleanup;
  226. }
  227. for(i=1;i<lastchan+1;i++){
  228. if(select[i-1]){
  229. if((psf_sndWriteFloatFrames(ofd[i-1],frame +(i-1),1))<0){
  230. fprintf(stderr,"Channelx: Write [channel %d] failed.\n\n",i);
  231. //RWD
  232. //sndunlink(ofd[i-1]);
  233. writefiles--;
  234. if(writefiles==0)
  235. break;
  236. else
  237. continue; //may be other files we can still write to...
  238. }
  239. }
  240. }
  241. total_frames++;
  242. if((total_frames % (inprops.srate/2)) == 0){
  243. printf("%.2lf secs\r",(double)total_frames / (double)inprops.srate);
  244. fflush(stdout);
  245. }
  246. }
  247. printf("%.4lf secs\n",(double)total_frames / (double)inprops.srate);
  248. printf("%d files created.\n",writefiles);
  249. cleanup:
  250. psf_sndClose(ifd);
  251. for(i=0;i < MAXFILES; i++){
  252. if(ofd[i] >= 0)
  253. psf_sndClose(ofd[i]);
  254. }
  255. free(frame);
  256. psf_finish();
  257. return 0;
  258. }