chorder.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. * Copyright (c) 1983-2023 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. /* chorder : reorder channels in m/c file */
  21. /* Jan 2010: corrected behaviour with out of range order chars */
  22. /* July 2010 removed spurious premature call to usage() */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <math.h>
  27. #include <portsf.h>
  28. /* set size of multi-channel frame-buffer */
  29. #define NFRAMES (1024)
  30. /* TODO define program argument list, excluding flags */
  31. enum {ARG_PROGNAME,ARG_INFILE,ARG_OUTFILE,ARG_ORDERSTRING,ARG_NARGS};
  32. #define N_BFORMATS (10)
  33. static const int bformats[N_BFORMATS] = {2,3,4,5,6,7,8,9,11,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. {
  40. fprintf(stderr,"\nCDP MCTOOLS: CHORDER V1.2 (c) RWD,CDP 2009,2010\n");
  41. fprintf(stderr,
  42. "Reorder soundfile channels.\n"
  43. "Usage: chorder infile outfile orderstring\n"
  44. " orderstring = any combination of characters a-z inclusive.\n"
  45. " Infile channels are mapped in order as a=1,b=2...z=26\n"
  46. " (For example: channels in a 4-channel file are represented by the\n"
  47. " characters abcd; any other character is an error).\n"
  48. " Characters must be lower case, and may be used more than once.\n"
  49. " Duplicate characters duplicate the corresponding input channel.\n"
  50. " The zero character (0) may be used to set a silent channel.\n"
  51. " A maximum of 26 channels is supported for both input and output.\n"
  52. " NB: infile (WAVEX) speaker positions are discarded.\n"
  53. " The .amb extension is supported for the outfile.\n\n"
  54. );
  55. }
  56. int main(int argc, char* argv[])
  57. {
  58. PSF_PROPS inprops,outprops;
  59. long framesread;
  60. /* init all dynamic resources to default states */
  61. unsigned int i;
  62. int halfsec;
  63. unsigned int framepos;
  64. long outsize;
  65. int ifd = -1,ofd = -1;
  66. int error = 0;
  67. PSF_CHPEAK* peaks = NULL;
  68. psf_format outformat = PSF_FMT_UNKNOWN;
  69. unsigned long nframes = 1;
  70. float* inframe = NULL;
  71. float* outframe = NULL;
  72. float* orderptr[26];
  73. char* argstring = NULL;
  74. unsigned int rootchar = 'a';
  75. unsigned int maxchar = 'z';
  76. unsigned int nchars,nzeros = 0;
  77. unsigned int max_inchar;
  78. MYLONG peaktime;
  79. /* CDP version number */
  80. if(argc==2 && (stricmp(argv[1],"--version")==0)){
  81. printf("1.2.\n");
  82. return 0;
  83. }
  84. /* process any optional flags: remove this block if none used! */
  85. if(argc > 1){
  86. char flag;
  87. while(argv[1][0] == '-') {
  88. flag = argv[1][1];
  89. switch(flag){
  90. /*TODO: handle any flag arguments here */
  91. case('\0'):
  92. printf("Error: missing flag name\n");
  93. return 1;
  94. default:
  95. break;
  96. }
  97. argc--;
  98. argv++;
  99. }
  100. }
  101. if(argc < ARG_NARGS){
  102. printf("insufficient arguments.\n");
  103. usage();
  104. return 1;
  105. }
  106. /* initial check of charstring */
  107. argstring = argv[ARG_ORDERSTRING];
  108. nchars = strlen(argstring);
  109. if(nchars > 26) {
  110. printf("error: order string too long.\n");
  111. return 1;
  112. }
  113. /* always startup portsf */
  114. if(psf_init()){
  115. printf("unable to start portsf\n");
  116. return 1;
  117. }
  118. ifd = psf_sndOpen(argv[ARG_INFILE],&inprops,0);
  119. if(ifd < 0){
  120. printf("Error: unable to open infile %s\n",argv[ARG_INFILE]);
  121. error++;
  122. goto exit;
  123. }
  124. outsize = psf_sndSize(ifd);
  125. if(outsize <= 0){
  126. fprintf(stderr,"chorder: infile is empty!\n");
  127. psf_sndClose(ifd);
  128. return 1;
  129. }
  130. inframe = (float*) malloc(nframes * inprops.chans * sizeof(float));
  131. if(inframe==NULL){
  132. puts("No memory!\n");
  133. error++;
  134. goto exit;
  135. }
  136. /* final validate and parse of charstring */
  137. max_inchar = rootchar;
  138. for(i=0;i < nchars;i++){
  139. unsigned int thischar = argstring[i];
  140. // printf("reading char %c (%d)\n",thischar,thischar);
  141. unsigned int chindex;
  142. if(thischar != '0' && (thischar < rootchar || thischar > maxchar)){
  143. printf("illegal character in order string: %c\n",thischar);
  144. goto exit;
  145. }
  146. if(thischar =='0'){
  147. // printf("setting channel %d to zero.\n",i);
  148. orderptr[i] = NULL;
  149. nzeros++;
  150. }
  151. else{
  152. if(thischar > max_inchar)
  153. max_inchar = thischar;
  154. chindex = thischar - rootchar;
  155. orderptr[i] = &inframe[chindex];
  156. }
  157. }
  158. if(nzeros==nchars)
  159. printf("Warning: order string is all zeros - a silent file will be made!\n");
  160. else{
  161. /* count inclusively! */
  162. if(inprops.chans < (max_inchar - rootchar + 1)){
  163. printf("File has %d channels; order string defines non-existent channels.\n",inprops.chans);
  164. printf("For this file, maximum character is %c\n",rootchar+inprops.chans-1);
  165. goto exit;
  166. }
  167. }
  168. /* check file extension of outfile name, so we use correct output file format*/
  169. outformat = psf_getFormatExt(argv[ARG_OUTFILE]);
  170. if(outformat == PSF_FMT_UNKNOWN){
  171. printf("outfile name %s has unsupported extension.\n"
  172. "Use any of .wav, .aiff, .aif, .afc, .aifc, .amb\n",argv[ARG_OUTFILE]);
  173. error++;
  174. goto exit;
  175. }
  176. inprops.format = outformat;
  177. outprops = inprops;
  178. outprops.chans = nchars;
  179. if(!is_legalsize(outsize,&outprops)){
  180. fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
  181. return 1;
  182. }
  183. /* any speaker assignment etc invalidated! */
  184. if(outformat == PSF_STDWAVE) {
  185. outprops.chformat = MC_STD;
  186. outprops.format = PSF_WAVE_EX;
  187. }
  188. if(outformat==PSF_WAVE_EX){
  189. int matched = 0;
  190. for(i=0;i < N_BFORMATS;i++) {
  191. if(inprops.chans == bformats[i]){
  192. matched = 1;
  193. break;
  194. }
  195. }
  196. if(!matched){
  197. printf("WARNING: No B-format definition for %d-channel file.\n",outprops.chans);
  198. }
  199. outprops.chformat = MC_BFMT;
  200. outprops.format = PSF_WAVE_EX;
  201. }
  202. outframe = malloc(sizeof(float) * nchars);
  203. peaks = (PSF_CHPEAK*) malloc(outprops.chans * sizeof(PSF_CHPEAK));
  204. if(peaks == NULL){
  205. puts("No memory!\n");
  206. error++;
  207. goto exit;
  208. }
  209. ofd = psf_sndCreate(argv[ARG_OUTFILE],&outprops,0,0,PSF_CREATE_RDWR);
  210. if(ofd < 0){
  211. printf("Error: unable to create outfile %s\n",argv[ARG_OUTFILE]);
  212. error++;
  213. goto exit;
  214. }
  215. halfsec = inprops.srate / 2;
  216. framepos = 0;
  217. printf("processing....\n");
  218. while ((framesread = psf_sndReadFloatFrames(ifd,inframe,1)) > 0){
  219. float val;
  220. for(i=0;i < nchars;i++){
  221. if(orderptr[i] == NULL)
  222. val = 0.0f;
  223. else
  224. val = *orderptr[i];
  225. outframe[i] = val;
  226. }
  227. if(psf_sndWriteFloatFrames(ofd,outframe,1) != 1){
  228. printf("Error writing to outfile\n");
  229. error++;
  230. break;
  231. }
  232. if((framepos % halfsec) == 0){
  233. printf("%.2lf secs\r",(double) framepos / (double) outprops.srate);
  234. fflush(stdout);
  235. }
  236. framepos++;
  237. }
  238. if(framesread < 0) {
  239. printf("Error reading infile. Outfile is incomplete.\n");
  240. error++;
  241. }
  242. printf("\n%.4lf secs\nWritten %d frames to %s\n",(double)framepos / (double) outprops.srate,framepos,argv[ARG_OUTFILE]);
  243. if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
  244. printf("PEAK values:\n");
  245. for(i=0; i < outprops.chans; i++){
  246. double val, dbval;
  247. val = (double) peaks[i].val;
  248. if(val > 0.0){
  249. dbval = 20.0 * log10(val);
  250. printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
  251. val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) outprops.srate);
  252. }
  253. else{
  254. printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
  255. val,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) outprops.srate);
  256. }
  257. }
  258. }
  259. printf("\n");
  260. exit:
  261. if(ifd >= 0)
  262. psf_sndClose(ifd);
  263. if(ofd >= 0)
  264. psf_sndClose(ofd);
  265. if(inframe)
  266. free(inframe);
  267. if(outframe)
  268. free(outframe);
  269. if(peaks)
  270. free(peaks);
  271. psf_finish();
  272. return error;
  273. }