瀏覽代碼

initial commit

richarddobson 3 年之前
父節點
當前提交
519ff0cd64

+ 81 - 0
dev/externals/mctools/CMakeLists.txt

@@ -0,0 +1,81 @@
+if(APPLE)
+  set(CMAKE_C_FLAGS "-O2 -Wall -mmacosx-version-min=10.8 -Dunix -fomit-frame-pointer -funroll-loops")
+  set(CMAKE_CXX_FLAGS "-O2 -Wall -mmacosx-version-min=10.8 -Dunix -fomit-frame-pointer -funroll-loops -std=c++11 -stdlib=libc++")
+#  SET(CMAKE_EXE_LINKER_FLAGS "-static")
+else()
+  if(MINGW)
+    set(CMAKE_C_FLAGS "-O3 -DWIN32 -D_WIN32 -fomit-frame-pointer  -funroll-loops")
+  else()
+    set(CMAKE_C_FLAGS "-O3 -Wall -Dlinux -Dunix -fomit-frame-pointer -funroll-loops")
+  endif()
+endif()
+
+link_directories(../lib)
+
+include_directories(../../../include ../include)
+
+add_executable(abfpan abfpan.cpp)
+target_link_libraries(abfpan portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(abfpan)
+
+add_executable(abfpan2 abfpan2.cpp)
+target_link_libraries(abfpan2 portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(abfpan2)
+
+add_executable(abfdcode abfdcode.cpp)
+target_link_libraries(abfdcode portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(abfdcode)
+
+add_executable(fmdcode fmdcode.c fmhfuncs.c)
+target_link_libraries(fmdcode portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(fmdcode)
+
+add_executable(channelx channel.c)
+target_link_libraries(channelx portsf sfsys m ${EXTRA_LIBRARIES})
+
+my_install(channelx)
+
+add_executable(chorder chorder.c)
+target_link_libraries(chorder portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(chorder)
+
+add_executable(chxformat chxformat.c)
+target_link_libraries(chxformat portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(chxformat)
+
+add_executable(copysfx copysf.c)
+target_link_libraries(copysfx portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(copysfx)
+
+add_executable(interlx interlx.c)
+target_link_libraries(interlx portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(interlx)
+
+add_executable(nmix nmix.c)
+target_link_libraries(nmix portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(nmix)
+
+add_executable(njoin njoin.c)
+target_link_libraries(njoin portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(njoin)
+
+add_executable(rmsinfo rmsinfo.cpp)
+target_link_libraries(rmsinfo portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(rmsinfo)
+
+add_executable(sfprops sfprops.c)
+target_link_libraries(sfprops portsf sfsys ${EXTRA_LIBRARIES})
+
+my_install(sfprops)
+

+ 189 - 0
dev/externals/mctools/abfdcode.cpp

@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+//abfdcode.cpp  : write mono wave file into ambisonic B-format
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "portsf.h"
+
+#ifdef unix
+/* in portsf.lib */
+extern  "C" {
+    int stricmp(const char *a, const char *b);
+}
+#endif
+
+typedef struct abf_samp {
+	float W;
+	float X;
+	float Y;
+	float Z;	
+} ABFSAMPLE;
+
+int main(int argc,char *argv[])
+{
+	int i,ifd, ofd;
+	long outchans = 4;
+	long outsize;
+	char *sfname;
+	bool write_wavex = false;
+	ABFSAMPLE abfsample;
+	float frame[4];
+	PSF_PROPS props;
+	PSF_CHPEAK peaks[4];
+	long inchans;
+    MYLONG peaktime;
+
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.2.1\n");
+        return 0;
+    }
+    
+	if(argc < 3){
+		printf("\nCDP MCTOOLS: ABFDCODE v 1.2.1: CDP 1999,2004,2005\n"
+				"Horizontal B Format Decoder\n"
+				"usage: abfdcode [-x] infile outfile\n"
+				"       -x    :   write WAVE_EX (Quad) outfile format\n"
+				"                (requires .wav extension)\n"
+				"NB: infile must have 3 or 4 channels\n"
+                "UPDATE 2009: This program is now replaced by FMDCODE, \n"
+                "and may be omitted in future updates to the Toolkit.\n"
+                "For this task use fmdcode with e.g. layout 4.\n"
+				);
+		return 1;
+	}
+	while(argv[1][0] =='-'){		
+		switch(argv[1][1]){
+		case('x'):
+			write_wavex = true;
+			break;
+		default:
+			fprintf(stderr,"abfdecode: error: illegal flag option %s\n",argv[1]);
+			return 1;
+		}
+		argc--; argv++;
+	}
+	if(argc < 3){
+		fprintf(stderr,"CDP MCTOOLS: ABFDCODE.EXE: CDP 1999,2005\nHorizontal B Format Decoder\nusage: abfdcode [-x] infile outfile\n");
+		return 1;
+	}
+	if(psf_init()){
+		fprintf(stderr,"abfdcode: startup failure.\n");
+		return 1;
+	}
+	
+	sfname = argv[2];
+	
+	ifd = psf_sndOpen(argv[1],&props,0);
+	if(ifd < 0){
+		fprintf(stderr,"unable toopen infile %s\n",argv[1]);
+		return 1;
+	}
+
+	inchans = props.chans;
+	if(!(inchans == 3 || inchans == 4)){
+		fprintf(stderr,"Sorry: infile is not first-order\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+
+	outsize = psf_sndSize(ifd);
+	if(outsize <= 0){
+		fprintf(stderr,"infile is empty!\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+	
+	props.chformat = STDWAVE;
+	props.chans = 4;
+    if(!is_legalsize(outsize,&props)){
+        fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
+        return 1;
+    }
+    
+    
+	if(write_wavex){
+		props.chformat = MC_QUAD;
+		props.format = PSF_WAVE_EX;
+	}
+	//ofd = sndcreat_formatted(sfname,outsize * outchans,stype,outchans,srate,CDP_CREATE_NORMAL);
+	ofd = psf_sndCreate(sfname,&props,0,0,PSF_CREATE_RDWR);
+	if(ofd < 0){
+		fprintf(stderr,"can't create outfile %s.\n",sfname);
+		psf_sndClose(ifd);
+		return 1;
+	}
+	
+
+	int got, halfsec = props.srate / 2;
+	unsigned int framepos = 0;
+	printf("\ndoing b-format decoding:\n");
+	while((got = psf_sndReadFloatFrames(ifd,(float *) &abfsample,1))==1){
+		//this_samp	= 0.5 * p_iosc->tick(1000);
+		float aw = abfsample.W;
+		float ax = abfsample.X * 0.707f;
+		float ay = abfsample.Y * 0.707f;
+		frame[0] = 0.3333f * (aw + ax + ay);
+		frame[1] = 0.3333f * (aw + ax - ay);
+		frame[2] = 0.3333f * (aw - ax + ay);
+		frame[3] = 0.3333f * (aw - ax - ay);
+
+		if(0 > psf_sndWriteFloatFrames(ofd,frame,1)){
+			fprintf(stderr,"error writing sample block  %ld\n",got * outchans);
+			psf_sndClose(ifd);
+			psf_sndClose(ofd);
+			return 1;
+		}
+		if(framepos % halfsec==0) {
+			printf("%.2lf secs\r",(double)framepos / (double) props.srate);
+            fflush(stdout);
+        }
+		framepos++;
+	}
+
+	if(got != 0){
+		fprintf(stderr,"warning: not all data was read\n");
+	}
+	printf("\n%.4lf secs\nWritten %d quad frames to %s\n",(double)framepos / (double) props.srate,framepos,sfname);
+    if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
+        printf("PEAK values:\n");
+        for(i=0; i < outchans; i++){
+            double val, dbval;
+            val = (double) peaks[i].val;
+            if(val > 0.0){
+                dbval = 20.0 * log10(val);
+                printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+                        val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props.srate);
+            }
+            else{
+                printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
+                    val,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props.srate); 
+            }
+        }
+              
+    }
+    psf_sndClose(ifd);
+	psf_sndClose(ofd);
+	psf_finish();
+	return 0;
+}

+ 180 - 0
dev/externals/mctools/abfdcode2.cpp

@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+//abfdcode2.cpp  : decode to std wavex speaker positions
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+extern "C"{
+#include <sfsys.h>
+
+}
+
+typedef struct abf_samp {
+	float W;
+	float X;
+	float Y;
+	float Z;	
+} ABFSAMPLE;
+
+int main(int argc,char *argv[])
+{
+	int ifd, ofd;
+	long outchans = 4;
+	long outsize;
+	char *sfname;
+	bool write_wavex = false;
+	ABFSAMPLE abfsample;
+	float frame[4];
+	SFPROPS props;
+	CHPEAK peaks[4];
+	long inchans;
+
+	if(argc < 3){
+		printf("\nCDP MCTOOLS: ABFDCODE2 v 1.0: RWD,CDP 2009\n"
+				"Horizontal B Format Decoder\n"
+				"usage: abfdcode2 infile outfile layout\n"
+				"       (wavex layouts require .wav extension)\n"
+				
+				);
+		return 1;
+	}
+	while(argv[1][0] =='-'){		
+		switch(argv[1][1]){
+		case('x'):
+			write_wavex = true;
+			break;
+		default:
+			fprintf(stderr,"abfdecode: error: illegal flag option %s\n",argv[1]);
+			return 1;
+		}
+		argc--; argv++;
+	}
+	if(argc < 3){
+		fprintf(stderr,"CDP MCTOOLS: ABFDCODE.EXE: CDP 1999,2005\nHorizontal B Format Decoder\nusage: abfdcode [-x] infile outfile\n");
+		return 1;
+	}
+	if(sflinit("abfdcode")){
+		fprintf(stderr,"unable to initialize sfsys\n");
+		return 1;
+	}
+	
+	sfname = argv[2];
+	
+	ifd = sndopenEx(argv[1],0,CDP_OPEN_RDONLY);
+	if(ifd < 0){
+		fprintf(stderr,"unable toopen infile %s\n",argv[1]);
+		return 1;
+	}
+
+	if(!snd_headread(ifd,&props)){
+		fprintf(stderr,"unable to read infile header data\n");
+		sndcloseEx(ifd);
+		return 1;
+	}
+	if(!props.type==wt_wave){
+		fprintf(stderr,"infile is not a soundfile\n");
+		sndcloseEx(ifd);
+		return 1;
+	}
+	inchans = props.chans;
+	if(!(inchans == 3 || inchans == 4)){
+		fprintf(stderr,"Sorry: infile is not first-order\n");
+		sndcloseEx(ifd);
+		return 1;
+	}
+
+	outsize = sndsizeEx(ifd) / inchans;
+	if(outsize <= 0){
+		fprintf(stderr,"infile is empty!\n");
+		sndcloseEx(ifd);
+		return 1;
+	}
+	
+
+	//srate = props.srate;
+	//stype = props.samptype == FLOAT32 ? SAMP_FLOAT : SAMP_SHORT;
+	props.chformat = STDWAVE;
+	props.chans = 4;
+	if(write_wavex){
+		props.chformat = MC_QUAD;
+		props.format = WAVE_EX;
+	}
+	//ofd = sndcreat_formatted(sfname,outsize * outchans,stype,outchans,srate,CDP_CREATE_NORMAL);
+	ofd = sndcreat_ex(sfname,outsize * outchans,&props,SFILE_CDP,CDP_CREATE_NORMAL);
+	if(ofd < 0){
+		fprintf(stderr,"can't create outfile %s : %s\n",sfname,sferrstr());
+		//delete p_iosc;
+		//delete p_sintable;
+		sndcloseEx(ifd);
+		return 1;
+	}
+	peaks[0].value = peaks[1].value = peaks[2].value = peaks[3].value = 0.0f;
+	peaks[0].position = peaks[1].position = peaks[2].position = peaks[3].position = 0;
+
+	int got,quartersec = props.srate / 4;
+	unsigned int framepos = 0;
+	printf("\ndoing b-format decoding:\n");
+	while((got = fgetfbufEx((float *) &abfsample,inchans,ifd,0))==inchans){
+		int i;
+		//this_samp	= 0.5 * p_iosc->tick(1000);
+		float aw = abfsample.W;
+		float ax = abfsample.X * 0.707f;
+		float ay = abfsample.Y * 0.707f;
+		frame[0] = 0.3333f * (aw + ax + ay);
+		frame[1] = 0.3333f * (aw + ax - ay);
+		frame[2] = 0.3333f * (aw - ax + ay);
+		frame[3] = 0.3333f * (aw - ax - ay);
+
+		if(0 > fputfbufEx(frame,outchans,ofd)){
+			fprintf(stderr,"error writing sample block  %ld\n",got * outchans);
+			sndcloseEx(ifd);
+			sndcloseEx(ofd);
+			return 1;
+		}
+		for(i=0;i < 4;i++){
+			float val;
+			val= (float)fabs(frame[i]);
+			if(val > peaks[i].value) {
+				peaks[i].value = val;
+				peaks[i].position = framepos;
+			}
+		}
+		if(framepos % quartersec==0)
+			printf("%.2lf secs\r",(double)framepos / (double) props.srate);
+		framepos++;
+	}
+
+	if(got != 0){
+		fprintf(stderr,"warning: not all data was read\n");
+	}
+	printf("\n%.4lf secs\nWritten %d quad frames to %s\n",(double)framepos / (double) props.srate,framepos,sfname);
+	printf("PEAK values:\n");
+	printf("CH 1: %.4f at frame %ld:\t%.4f secs\n",peaks[0].value,peaks[0].position,(double)peaks[0].position / (double) props.srate);
+	printf("CH 2: %.4f at frame %ld:\t%.4f secs\n",peaks[1].value,peaks[1].position,(double)peaks[1].position / (double) props.srate);
+	printf("CH 3: %.4f at frame %ld:\t%.4f secs\n",peaks[2].value,peaks[2].position,(double)peaks[2].position / (double) props.srate);
+	printf("CH 4: %.4f at frame %ld:\t%.4f secs\n",peaks[3].value,peaks[3].position,(double)peaks[3].position / (double) props.srate);
+	sndputpeaks(ofd,4,peaks);
+	sndcloseEx(ifd);
+	sndcloseEx(ofd);
+	sffinish();
+	return 0;
+}

+ 276 - 0
dev/externals/mctools/abfpan.cpp

@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+//abfpan.cpp  : write mono wave file into ambisonic B-format
+// Dec 2005 support .amb extension, and 3ch output
+// Jan 2010: corrected usage message about -b and -x
+// Nov 2013: updated usage message formatting, infile must be mono
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "portsf.h"
+
+#ifdef unix
+/* in portsf.lib */
+extern "C" {
+    int stricmp(const char *a, const char *b);
+}
+#endif
+
+#ifndef TWOPI
+#define TWOPI	(6.283185307)
+#endif
+typedef struct abf_samp {
+	float W;
+	float X;
+	float Y;
+	float Z;	
+} ABFSAMPLE;
+
+
+enum {ARG_PROGNAME, ARG_INFILE, ARG_OUTFILE,ARG_STARTPOS, ARG_ENDPOS,ARG_NARGS};
+void usage()
+{
+	fprintf(stderr,"CDP MCTOOLS V1.5.3 (c) RWD,CDP 2009,2010,2013\n"
+				   "ABFPAN:  apply fixed or orbiting 1st-order B-Format pan to infile\n");
+	fprintf(stderr,"usage : abfpan [-b][-x][-oN] infile outfile startpos endpos\n");
+	fprintf(stderr,"    infile:   input soundfile, must be mono\n");
+	fprintf(stderr,"    startpos: 0.0 <= startpos <= 1.0 (0.0 and 1.0 = Centre Front)\n");
+	fprintf(stderr,"    endpos:   endpos < 0.0 gives anticlockwise rotation,\n"
+				   "                endpos > 0.0 gives clockwise rotation.\n"
+				   "                Units give number of revolutions, fraction gives final position\n"
+				   "                Set endpos = startpos for fixed pan\n");
+	fprintf(stderr,"    -b:       write output as horizontal Ambisonic B-format (.amb),\n"
+                   "                (i.e. bypass B-Format decoding).\n"
+			       "    -x:       write (WAVE_EX) format file (.wav). \n"			   
+				   "                Default: write standard m/c soundfile (WAVE,AIFF).\n"
+                   "                NB: -b overrides -x - no meaning in using both.\n"
+				   "    -oN:      number of B-Format output channels: N = 3 or 4 only.\n"
+				   "                Default: write 4-ch file.\n"
+                   "    See also ABFPAN2 for 2nd order version with fixed height.\n"
+	);
+    fprintf(stderr,"\n");
+}
+
+
+
+#define SYN_BUFLEN	(32768)
+#define TABLEN (1024)
+int main(int argc,char *argv[])
+{
+	int ifd, ofd;
+	int srate = 44100;
+	int outchans = 4;
+    MYLONG peaktime;
+	long outsize;	
+	float this_samp;
+	char *sfname;
+	double angle_incr;
+	double start_angle = 0.0;
+	double startpos,endpos;
+	
+	ABFSAMPLE abfsample;
+	PSF_PROPS props;
+	PSF_CHPEAK peaks[4];
+
+	bool write_bformat = false;
+	bool write_wavex = false;
+	int iarg = outchans;
+
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.5.2.\n");
+        return 0;
+    }
+    
+	if(argc < 5){
+		usage();
+		return 1;
+	}
+
+	if(psf_init()){
+		fprintf(stderr,"abfpan2: Startup failure.\n");
+		return 1;
+	}
+	
+	while(argv[1][0] =='-'){
+		
+		switch(argv[1][1]){
+		case('b'):
+			write_bformat = true;
+			break;
+
+		case('x'):
+			write_wavex = true;
+			break;
+		case('o'):
+			if(argv[1][2]=='\0'){
+				fprintf(stderr,"abfpan: error: -o flag requires channel value\n");
+				return 1;
+			}
+			iarg = atoi(&(argv[1][2]));
+			if(!(iarg == 3 || iarg == 4)){
+				fprintf(stderr,"abfpan: error: invalid channel value for -o flag\n");
+				return 1;
+			}
+
+			break;
+		default:
+			fprintf(stderr,"abfpan: error: illegal flag option %s.\n",argv[1]);
+			return 1;
+		}
+
+		argc--; argv++;
+	}
+
+	if(argc != 5){
+		usage();
+		return 1;
+	}
+
+	if(write_bformat)
+		outchans = iarg;
+    
+	sfname = argv[ARG_INFILE];
+	startpos = atof(argv[ARG_STARTPOS]);
+	if(startpos < 0.0 || startpos > 1.0){
+		fprintf(stderr,"abfpan: startpos %.4lf out of range: must be between 0.0 and 1.0.\n",startpos);
+		return 1;
+	}
+
+	endpos = atof(argv[ARG_ENDPOS]);
+
+
+
+	ifd = psf_sndOpen(sfname,&props,0);
+	if(ifd < 0){
+		fprintf(stderr,"abfpan: unable to open infile %s.\n",argv[1]);
+		return 1;
+	}
+	if(props.chans != 1){
+		fprintf(stderr,"abfpan: infile must be mono.\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+
+	outsize = psf_sndSize(ifd);
+	if(outsize <= 0){
+		fprintf(stderr,"abfpan: infile is empty!\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+    srate = props.srate;
+	props.chans = outchans;
+    if(!is_legalsize(outsize,&props)){
+        fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
+        return 1;
+    }
+                
+	start_angle = - (TWOPI * startpos);	   //we think of positive as clockwise at cmdline!
+	angle_incr = TWOPI / outsize;
+	angle_incr *= (endpos - startpos);
+	
+	if(write_wavex){
+		props.format = PSF_WAVE_EX;
+		props.chformat = MC_QUAD;
+	}
+	if(write_bformat)
+		props.chformat = MC_BFMT;
+	ofd = psf_sndCreate(argv[ARG_OUTFILE],&props,0,0,PSF_CREATE_RDWR);
+	if(ofd < 0){
+		fprintf(stderr,"abfpan: can't create outfile %s.\n",argv[ARG_OUTFILE]);	
+		return 1;
+	}
+
+	int i,got;
+	int half_sec = srate / 4;
+	long total_frames = 0;
+	double d_srate = (double)srate;
+
+	abfsample.Z = 0.0f;
+	for(i=0; i < outchans; i++){
+		peaks[i].val = 0.0f;
+		peaks[i].pos = 0;
+	}
+	//should make one 360deg rotate over duration
+	//TODO: make lookup_sin and lookup_cos ugens, taking angle arg
+	if(write_bformat)
+		printf("\nWriting B-Format file:\n");
+	else
+		printf("\n");
+	while((got = psf_sndReadFloatFrames(ifd,&this_samp,1))==1){		
+		abfsample.W = (float) (this_samp * 0.707);
+        abfsample.X = (float) (this_samp * cos(start_angle));
+		abfsample.Y	= (float) (this_samp * sin(start_angle));
+
+		//set this for periphonic; otherwise = 0.0 for horizontal_only
+		//abfsample.Z = (float) (this_samp*0.25);
+		if(!write_bformat){
+			//decode into quad file
+			float aw = abfsample.W;
+			float ax = abfsample.X * 0.707f;
+			float ay = abfsample.Y * 0.707f;
+            /* ignore wxyz names  - this is now handy container for quad speaker feeds*/
+			abfsample.W = 0.33333f * (aw + ax + ay); /* front L */
+			abfsample.X = 0.33333f * (aw + ax - ay); /* front R */
+			abfsample.Y = 0.33333f * (aw - ax + ay); /* rear  L */
+			abfsample.Z = 0.33333f * (aw - ax - ay); /* rear  R */
+		}
+		if(0 > psf_sndWriteFloatFrames(ofd,(float*)  &abfsample,1)){
+			fprintf(stderr,"error writing abf sample frame  %ld\n",total_frames);
+			return 1;
+		}
+		start_angle -= angle_incr;
+		total_frames++;		
+		if(total_frames % half_sec ==0) {
+			printf("%.2lf secs\r",(double)total_frames / d_srate);
+            fflush(stdout);
+        }
+	}
+
+	if(got != 0){
+		fprintf(stderr,"abfpan: warning: not all data was read.\n");
+	}
+
+	printf("%.4lf secs\nwritten %ld %d-ch sample frames to %s\n",(double)outsize / d_srate,outsize,outchans, argv[ARG_OUTFILE]);
+	if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
+		printf("PEAK values:\n");
+		for(i=0; i < outchans; i++){
+            double val, dbval;
+            val = (double) peaks[i].val;
+            if(val > 0.0){
+                dbval = 20.0 * log10(val);
+                printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+                       val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props.srate);
+            }
+            else{
+                printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
+                        val, (unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props.srate); 
+            }
+        }
+        
+	}
+	printf("\n");
+	psf_sndClose(ifd);
+	psf_sndClose(ofd);
+	psf_finish();
+	return 0;
+}

+ 296 - 0
dev/externals/mctools/abfpan2.cpp

@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+//abfpan2.cpp  : write mono wave file into ambisonic B-format
+// Dec 2005 support .amb extension, and 3ch output
+// OCT 2009 portsf version, with 2nd-order encoding
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include "portsf.h"
+
+#ifndef M_PI
+#define M_PI (3.141592654)
+#endif
+#ifndef TWOPI
+#define TWOPI	(6.283185307)
+#endif
+
+#ifdef unix
+/* in portsf.lib */
+extern "C" {
+    int stricmp(const char *a, const char *b);
+}
+#endif
+
+enum {W,X,Y,Z,R,S,T,U,V};
+
+
+enum {ARG_PROGNAME, ARG_INFILE, ARG_OUTFILE,ARG_STARTPOS,ARG_ENDPOS,ARG_NARGS};
+
+void usage()
+{
+	fprintf(stderr,"\nCDP MCTOOLS V1.0.1 beta (c) RWD,CDP 2010"
+				   "\n\nABFPAN2:  apply fixed or orbiting 2nd-order B-Format pan to infile\n");
+	fprintf(stderr,"usage : abfpan2 [-gGAIN][-w] [-p[DEG]] infile outfile startpos endpos\n"
+                   "    infile : mono source.\n"
+                   "    outfile: 2nd order B-format output.\n"        
+	               "        0.0 <= startpos <= 1.0 (0.0 and 1.0 = Centre Front).\n");
+	fprintf(stderr,"    endpos : endpos < 0.0 gives anticlockwise rotation,\n"
+				   "            endpos > 0.0 gives clockwise rotation.\n"
+				   "            Units give number of revolutions, fraction gives final position\n"
+				   "            Set endpos = startpos for fixed pan\n"
+                   "    -gGAIN : scale infile amplitude by GAIN (GAIN > 0).\n"
+                   "    -w     : Write standard soundfile (wave, aiff)\n"
+                   "            Default: WAVEX B-Format; use .amb extension.\n"
+                   "    -p[DEG]: write full 9-channel (periphonic) B-Format file.\n"
+                   "        Default: write 5-channel (2nd-order horizontal) file.\n"
+                   "        DEG:  optional fixed height argument (degrees).\n"
+                   "             Range = -180  to +180,\n"
+                   "             where  -90 = nadir, +90 = zenith (directly above).\n"
+                   "             Default: DEG=0;  height channels (Z,R,S,T)  will be empty.\n"
+                   "    NB: this program does not create a decoded output.\n"
+                   "    Use FMDCODE to decode to choice of speaker layouts.\n"
+				   );
+    fprintf(stderr,"\n");
+}
+
+int main(int argc,char *argv[])
+{
+	int i,got,ifd, ofd;
+	long srate = 44100;
+	long outchans = 5;
+    long do_peri = 0;
+    int write_wav = 1;
+	MYLONG peaktime;
+	long outsize;	
+	float this_samp;
+	int half_sec;
+	long total_frames;
+	double d_srate;
+	char *sfname;
+	double angle_incr;
+	double start_angle = 0.0;
+	double startpos,endpos;
+    double gain = 1.0;
+    double degree=0.0,elevation = 0.0;  
+	
+	float abfsample[9];
+    float outframe[5];
+    float *p_frame;
+    
+	PSF_PROPS props;
+	PSF_CHPEAK *peaks = NULL;
+	
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.0.1b\n");
+        return 0;
+    }
+    
+	if(argc < 5){
+		usage();
+		return 1;
+	}
+
+	if(psf_init()){
+		fprintf(stderr,"\nabfpan2: Startup failure");
+		return 1;
+	}
+	
+	while(argv[1][0] =='-'){
+		switch(argv[1][1]){
+        case 'g':
+            if(argv[1][2] == '\0'){
+                fprintf(stderr,"abfpan2 Error: -g flag requires a value.\n");
+                return 1;
+            }
+            gain = atof(&argv[1][2]);
+            if(gain <= 0.0){
+                printf("abfpan2: gain value must be positive!\n");
+                return 1;
+            }
+            break;
+        case 'p':
+            if(argv[1][2] != '\0'){
+                degree = atof(&argv[1][2]);
+                if(degree < -180.0 || degree > 180.0){
+                    fprintf(stderr,"-p: degree value out of range.\n");
+                    return 1;
+                }
+                elevation = degree * (M_PI  / 180.0);
+            }
+            outchans = 9;
+            do_peri = 1;
+            break;
+        case 'w':
+            write_wav = 0;
+            break;
+		default:
+			fprintf(stderr,"\nabfpan: error: illegal flag option %s",argv[1]);
+			return 1;
+		}
+		argc--; argv++;
+	}
+
+	if(argc < ARG_NARGS ){
+		usage();
+		return 1;
+	}
+
+	sfname = argv[ARG_INFILE];
+	startpos = atof(argv[ARG_STARTPOS]);
+	if(startpos < 0.0 || startpos > 1.0){
+		fprintf(stderr,"abfpan2: startpos %.4lf out of range: must be between 0.0 and 1.0\n",startpos);
+		return 1;
+	}
+
+	endpos = atof(argv[ARG_ENDPOS]);
+	ifd = psf_sndOpen(sfname,&props,0);
+	if(ifd < 0){
+		fprintf(stderr,"abfpan2: unable toopen infile %s.\n",sfname);
+		return 1;
+	}
+
+    if(props.chans != 1){
+		fprintf(stderr,"abfpan2: infile must be mono.\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+
+	outsize = psf_sndSize(ifd);
+	if(outsize <= 0){
+		fprintf(stderr,"abfpan2: infile is empty!\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+    srate = props.srate;
+	props.chans = outchans;
+    if(!is_legalsize(outsize,&props)){
+        fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
+        return 1;
+    }
+    
+	start_angle = - (TWOPI * startpos);	   //we think of positive as clockwise at cmdline!
+	angle_incr = TWOPI / outsize;
+	angle_incr *= (endpos - startpos);
+    
+	
+    if(write_wav == 0)
+        props.format = PSF_STDWAVE;
+    else {
+        printf("Writing B-Format file.\n");
+	    props.format = PSF_WAVE_EX;
+        props.chformat = MC_BFMT;
+    }
+    
+    peaks = (PSF_CHPEAK*)  malloc(sizeof(PSF_CHPEAK) * outchans);
+    memset(peaks,0,sizeof(PSF_CHPEAK) * outchans);
+    
+    
+	ofd = psf_sndCreate(argv[ARG_OUTFILE],&props,0,0,PSF_CREATE_RDWR);
+	if(ofd < 0){
+		fprintf(stderr,"abfpan2: can't create outfile %s.\n",sfname);	
+		return 1;
+	}
+
+	half_sec = srate / 2;
+	total_frames = 0;
+	d_srate = (double)srate;
+	
+	//should make one 360deg rotate over duration
+	//TODO: make lookup_sin and lookup_cos ugens, taking angle arg
+	
+    if(do_peri)
+        p_frame = abfsample;
+    else
+        p_frame = outframe;
+    
+	while((got = psf_sndReadFloatFrames(ifd,&this_samp,1))==1){
+		double x,y,z,xx,yy,zz;
+        x = cos(start_angle);
+        y = sin(start_angle);
+        if(elevation ==0.0)
+            z = 0.0;
+        else
+            z = sin(elevation);
+        xx = x * x;
+        yy = y * y;
+        zz = z * z;
+        this_samp *= gain;
+        if(do_peri) {
+            abfsample[W] = (float) (this_samp * 0.7071);
+            abfsample[X] = (float) (this_samp * x);
+            abfsample[Y] = (float) (this_samp * y);
+            abfsample[Z] = (float) (this_samp * z);
+            abfsample[R] = (float) (this_samp * (1.5 * zz - 0.5));  /// ????
+            abfsample[S] = (float) (this_samp * (2.0 * z * x));
+            abfsample[T] = (float) (this_samp * (2.0 * y * z));
+            abfsample[U] = (float) (this_samp * (xx-yy));
+            abfsample[V] = (float) (this_samp * (2.0 * x * y));
+        }
+        else{
+            outframe[0]  = (float) (this_samp * 0.7071);
+            outframe[1]  = (float) (this_samp * x);
+            outframe[2]  = (float) (this_samp * y);
+            outframe[3] = (float) (this_samp * (xx-yy));
+            outframe[4] = (float) (this_samp * (2.0 * x * y));
+        }
+            
+		if(0 > psf_sndWriteFloatFrames(ofd, p_frame,1)){
+			fprintf(stderr,"abfpan2: error writing frame %ld\n",total_frames);
+			return 1;
+		}
+		start_angle -= angle_incr;
+		total_frames++;		
+		if(total_frames % half_sec ==0) {
+			printf("%.2lf secs\r",(double)total_frames / d_srate);
+            fflush(stdout);
+        }
+	}
+	if(got != 0){
+		fprintf(stderr,"abfpan2: warning: not all data was read.\n");
+	}
+	printf("%.4lf secs\nWritten %ld frames to %s.\n",(double)total_frames / d_srate,total_frames, argv[ARG_OUTFILE]);
+	if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
+		printf("PEAK values:\n");
+		for(i=0; i < outchans; i++){
+            double val, dbval;
+            val = (double) peaks[i].val;
+            if(val > 0.0){
+                dbval = 20.0 * log10(val);
+                printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+                       val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props.srate);
+            }
+            else{
+                printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
+                       val,(unsigned int)peaks[i].pos,(double)peaks[i].pos / (double) props.srate); 
+            }
+        }
+        
+	}
+
+	psf_sndClose(ifd);
+	psf_sndClose(ofd);
+	psf_finish();
+	return 0;
+}

+ 302 - 0
dev/externals/mctools/channel.c

@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The CDP System is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* channelx.c */
+//RWD MCTOOLS, portsf version Oct 2009
+// nothing special, but use PEAK chunk (reading it where available)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <ctype.h>
+#include <portsf.h>
+
+#ifndef _MAX_PATH
+#define _MAX_PATH (1024)
+#endif
+#define MAXFILES 16
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+
+void usage(void);
+//RWD.7.99 extended to get file extension from base name
+// so can be used without CDP_SOUND_EXT
+static void getbody(char*,char*,char *);
+
+void
+usage(void)
+{
+    fprintf(stderr,"\nCDP MCTOOLS: CHANNELX V1.6 (c) RWD, CDP 2010\n");
+    fprintf(stderr,
+            "Extract all channels from m/c file\n"
+            "usage: channelx [-oBASENAME] infile chan_no [chan_no...]\n"
+            //"\nusage:  channelx [-oBASENAME] infile"
+            "  -oBASENAME = base name (with extension) of outfiles (appended *_cN for ch N)\n"
+            "(NB: Channels of WAVE-EX files are written as standard soundfiles)\n"
+            );
+}
+
+#if defined(unix)
+#define SEP     '/'
+#else
+#define SEP     '\\'
+#endif
+
+void getbody(char *filename,char *body,char *ext)
+{
+    char *fn, *sl;
+
+    if((sl = strrchr(filename, SEP)) != 0)
+        sl++;
+    else
+        sl = filename;
+
+    for(fn = sl; *fn != '.' && *fn != '\0'; ) {
+        *body++ = *fn++;
+    }
+    *body++ = '\0';
+    //save extension
+    while(*fn != '\0')
+        *ext++ = *fn++;
+    *ext = '\0';
+}
+
+
+
+
+
+int main(int argc,char *argv[])
+{
+
+    int ifd = 0;                            /* Infile descriptor */
+    int ofd[MAXFILES];                      /* Outfile descriptors */
+    int i;                      /* Assorted indexes */
+    int inchans=1;                          /* Infile channels */
+    char filename[_MAX_PATH];       /* Infilename */
+    int select[MAXFILES];           /* Flags for each channel to MAXFILES */
+    int lastchan = 0;                       /* Maximum Requested channels */
+    int numchans = 0;                       /* number of channels extracted */
+    char body[100];                         /* Infile name prefix */
+    char ext[8];
+    char outext[8];                         /* output extension: to change .amb to .wav */
+    char *p_dot;
+    char ofile[_MAX_PATH];          /* Raw outfile name */
+    PSF_PROPS inprops;
+    int nframes =0, total_frames = 0;
+    float *frame = NULL;
+    int writefiles = 0;                     /* try to keep working even if one file fails...*/
+
+
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.6.\n");
+        return 0;
+    }
+    if(argc<2) {
+        usage();
+        return 1;
+    }
+
+    if(psf_init()) {
+        fprintf(stderr,"Startup failure.\n");
+        return 1;
+    }
+
+    body[0] = '\0';
+    ext[0] = '\0';
+
+    while(argv[1] != 0 && argv[1][0] == '-') {
+        if(strncmp(argv[1], "-o", 2) == 0) {
+            if(body[0] != '\0')
+                usage();
+            strcpy(body, &argv[1][2]);
+        }
+        argv++;
+        argc--;
+    }
+    if(argc < 2) {
+        usage();
+        return 1;
+    }
+
+    if(argv[1] != 0) {
+        sprintf(filename,"%s",argv[1]);
+        if((ifd = psf_sndOpen(filename,&inprops,0)) < 0) {
+            fprintf(stderr,"Channelx: Cannot open input file %s\n",argv[1]);
+            return 1;
+        }
+    }
+    argv++;
+
+    if(inprops.chans > MAXFILES){
+        fprintf(stderr,"Channelx: infile has too many channels!\n");
+        psf_sndClose(ifd);
+        return 1;
+    }
+    inchans = inprops.chans;
+    nframes = psf_sndSize(ifd);
+    if(nframes < 0){
+        fprintf(stderr,"Channelx: error reading infile size\n");
+        psf_sndClose(ifd);
+        return 1;
+    }
+    if(nframes==0){
+        fprintf(stderr,"Channelx: infile contains no data!\n");
+        psf_sndClose(ifd);
+        return 1;
+    }
+    nframes /= inchans;
+    //always create a standard file!
+    if(inprops.format == PSF_WAVE_EX) {
+        inprops.format = PSF_STDWAVE;
+        inprops.chformat = STDWAVE;
+    }
+    //that's all we need to know, now set one output channel
+    inprops.chans = 1;
+
+    frame = calloc(inchans,sizeof(float));
+    if(frame == NULL){
+        puts("Channelx: no memory for internal sample data\n");
+        psf_sndClose(ifd);
+        return 1;
+    }
+
+    for(i=0;i<MAXFILES;i++){
+        select[i] = 0;
+        ofd[i] = -1;
+    }
+
+
+    while(argv[1] != 0) {
+        int chn;
+
+        if(sscanf(argv[1],"%d",&chn) < 1){
+            fprintf(stderr,
+                    "Channelx: illegal channel argument %s\n\n",argv[1]);
+            goto cleanup;
+        }
+
+        if((chn > inchans) || (chn < 1)){
+            fprintf(stderr,"Channelx: channel argument out of range\n\n");
+            goto cleanup;
+        }
+        //check for duplicates
+        if(select[chn-1]==0){
+            select[chn-1] = 1;
+            if(chn > lastchan)
+                lastchan = chn;
+            numchans++;
+        }
+        else
+            fprintf(stderr,"Channelx: WARNING: duplicate channel number %d\n",chn);
+
+        argv++;
+        argc--;
+    }
+    if(numchans < 1) {              //RWD
+        fprintf(stderr, "channelx: must extract at least one channel\n");
+        goto cleanup;
+    }
+
+    writefiles = numchans;
+
+    if(body[0] == '\0')
+        getbody(filename,body,ext);
+
+    else if((p_dot = strrchr(body,'.')) != NULL){
+        //extension set in body arg
+        *p_dot++ = '\0';
+        sprintf(ext,".%s",p_dot);
+    }
+    //trap ambisonic file; single channels must be wav
+    strcpy(outext,ext);
+    if(stricmp(outext,".amb")==0)
+        strcpy(outext,".wav");
+    for(i=0;i<inchans;i++){
+        if(select[i]){
+            sprintf(ofile, "%s_c%d%s", body, i+1,outext);
+
+
+            if((ofd[i] = psf_sndCreate(ofile,&inprops,0,0,PSF_CREATE_RDWR)) < 0) {
+                fprintf(stderr,"Channelx: Failed to create %s\n\n",ofile);
+                goto cleanup;
+            }
+        }
+    }
+
+    printf("Extracting %d channels from '%s':\n%d sample frames\n",numchans,filename,nframes);
+
+    //stopwatch(1);
+    for(i=0;i < nframes; i++){
+        int got;
+        if(writefiles==0)
+            goto cleanup;
+
+        if((got = psf_sndReadFloatFrames(ifd,frame,1)) < 1){
+            if(got < 0)
+                fprintf(stderr,"error reading data from infile, after %d frames\n",i);
+            //sndunlink all outfiles?
+            else
+                break;
+            //goto cleanup;
+        }
+
+        for(i=1;i<lastchan+1;i++){
+            if(select[i-1]){
+                if((psf_sndWriteFloatFrames(ofd[i-1],frame +(i-1),1))<0){
+                    fprintf(stderr,"Channelx: Write [channel %d] failed.\n\n",i);
+                    //RWD
+                    //sndunlink(ofd[i-1]);
+                    writefiles--;
+                    if(writefiles==0)
+                        break;
+                    else
+                        continue;       //may be other files we can still write to...
+                }
+            }
+        }
+        total_frames++;
+        if((total_frames % (inprops.srate/2)) == 0){
+            printf("%.2lf secs\r",(double)total_frames / (double)inprops.srate);
+            fflush(stdout);
+        }
+    }
+    printf("%.4lf secs\n",(double)total_frames / (double)inprops.srate);
+    printf("%d files created.\n",writefiles);
+
+ cleanup:
+    psf_sndClose(ifd);
+
+    for(i=0;i < MAXFILES; i++){
+        if(ofd[i] >= 0)
+            psf_sndClose(ofd[i]);
+    }
+
+
+    free(frame);
+    psf_finish();
+    return 0;
+}

+ 297 - 0
dev/externals/mctools/chorder.c

@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/* chorder :  reorder channels in m/c file */
+/* Jan 2010: corrected behaviour with out of range order chars */
+/* July 2010 removed spurious premature call to usage() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <portsf.h>
+
+/* set size of multi-channel frame-buffer */
+#define NFRAMES (1024)
+
+/* TODO define program argument list, excluding flags */
+enum {ARG_PROGNAME,ARG_INFILE,ARG_OUTFILE,ARG_ORDERSTRING,ARG_NARGS};
+#define N_BFORMATS (10)
+static const int bformats[N_BFORMATS] = {2,3,4,5,6,7,8,9,11,16};
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+
+void usage(void)
+{
+    fprintf(stderr,"\nCDP MCTOOLS: CHORDER V1.2 (c) RWD,CDP 2009,2010\n");	
+    fprintf(stderr,
+            "Reorder soundfile channels.\n"
+            "Usage:  chorder infile outfile orderstring\n"
+            "  orderstring = any combination of characters a-z inclusive.\n"
+            "  Infile channels are mapped in order as a=1,b=2...z=26\n"
+            "  (For example: channels in a 4-channel file are represented by the\n"
+            "    characters abcd; any other character is an error).\n"
+            "  Characters must be lower case, and may be used more than once.\n"
+            "  Duplicate characters duplicate the corresponding input channel.\n"
+            "  The zero character (0) may be used to set a silent channel.\n"
+            "  A maximum of 26 channels is supported for both input and output.\n"
+            "  NB: infile (WAVEX) speaker positions are discarded.\n"
+            "  The .amb extension is supported for the outfile.\n\n"
+            );
+}
+
+
+int main(int argc, char* argv[])
+{
+	PSF_PROPS inprops,outprops;									
+	long framesread;	
+	/* init all dynamic resources to default states */
+	unsigned int i;
+    int halfsec;
+	unsigned int framepos;
+    long outsize;
+    int ifd = -1,ofd = -1;
+	int error = 0;
+	PSF_CHPEAK* peaks = NULL;	
+	psf_format outformat =  PSF_FMT_UNKNOWN;
+	unsigned long nframes = 1;
+	float* inframe = NULL;
+	float* outframe = NULL;
+    float* orderptr[26];
+    char* argstring = NULL;
+    unsigned int rootchar = 'a';
+    unsigned int maxchar = 'z';
+    unsigned int  nchars,nzeros = 0;
+    unsigned int max_inchar;
+    MYLONG peaktime;
+	
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.2.\n");
+        return 0;
+    }
+
+	/* process any optional flags: remove this block if none used! */
+	if(argc > 1){
+		char flag;
+		while(argv[1][0] == '-') {
+			flag = argv[1][1];
+			switch(flag){
+			/*TODO: handle any  flag arguments here */
+			case('\0'):
+				printf("Error: missing flag name\n");
+				return 1;
+			default:
+				break;
+			}
+			argc--;
+			argv++;
+		}
+	}
+
+	if(argc < ARG_NARGS){
+		printf("insufficient arguments.\n");
+		usage();
+		return 1;
+	}
+    
+    /* initial check of charstring */
+    argstring = argv[ARG_ORDERSTRING];
+    nchars = strlen(argstring);
+    if(nchars > 26) {
+        printf("error: order string too long.\n");
+        return 1;
+    }
+    
+	/*  always startup portsf */
+	if(psf_init()){
+		printf("unable to start portsf\n");
+		return 1;
+	}
+																							
+	ifd = psf_sndOpen(argv[ARG_INFILE],&inprops,0);															  
+	if(ifd < 0){
+		printf("Error: unable to open infile %s\n",argv[ARG_INFILE]);
+		error++;
+		goto exit;
+	}
+    outsize = psf_sndSize(ifd);
+	if(outsize <= 0){
+		fprintf(stderr,"chorder: infile is empty!\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+    inframe = (float*) malloc(nframes * inprops.chans * sizeof(float));
+	if(inframe==NULL){
+		puts("No memory!\n");
+		error++;
+		goto exit;
+	}
+    /* final validate and parse of charstring */
+    max_inchar = rootchar;
+    for(i=0;i < nchars;i++){
+        unsigned int thischar = argstring[i];
+//        printf("reading char %c (%d)\n",thischar,thischar);
+        unsigned int chindex;
+        if(thischar != '0' && (thischar < rootchar || thischar > maxchar)){
+            printf("illegal character in order string: %c\n",thischar);
+            goto exit;
+        }
+        if(thischar =='0'){
+//            printf("setting channel %d to zero.\n",i);
+            orderptr[i] = NULL;
+            nzeros++;
+        }
+        else{
+            if(thischar > max_inchar)
+                max_inchar = thischar;
+            chindex = thischar - rootchar;
+            orderptr[i] = &inframe[chindex];
+        }
+    }
+    if(nzeros==nchars)
+        printf("Warning: order string is all zeros - a silent file will be made!\n");
+    else{    
+        /* count inclusively! */
+        if(inprops.chans < (max_inchar - rootchar + 1)){
+            printf("File has %d channels; order string defines non-existent channels.\n",inprops.chans);
+            printf("For this file, maximum character is %c\n",rootchar+inprops.chans-1);
+            goto exit;
+        }
+    }
+	/* check file extension of outfile name, so we use correct output file format*/
+	outformat = psf_getFormatExt(argv[ARG_OUTFILE]);
+	if(outformat == PSF_FMT_UNKNOWN){
+		printf("outfile name %s has unsupported extension.\n"
+			"Use any of .wav, .aiff, .aif, .afc, .aifc, .amb\n",argv[ARG_OUTFILE]);
+		error++;
+		goto exit;
+	}
+	inprops.format = outformat;
+	outprops = inprops;
+	outprops.chans = nchars;
+    if(!is_legalsize(outsize,&outprops)){
+        fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
+        return 1;
+    }
+    /* any speaker assignment etc invalidated! */
+    if(outformat == PSF_STDWAVE) {
+        outprops.chformat = MC_STD;
+        outprops.format =  PSF_WAVE_EX;
+    }
+    
+    if(outformat==PSF_WAVE_EX){
+        int matched = 0;
+        for(i=0;i < N_BFORMATS;i++)	{
+            if(inprops.chans == bformats[i]){
+                matched = 1;
+                break;
+            }
+        }
+        if(!matched){
+            printf("WARNING: No B-format definition for %d-channel file.\n",outprops.chans);
+        }
+        outprops.chformat = MC_BFMT;
+        outprops.format =  PSF_WAVE_EX;
+    }
+    
+    outframe = malloc(sizeof(float) * nchars);
+    
+	peaks  =  (PSF_CHPEAK*) malloc(outprops.chans * sizeof(PSF_CHPEAK));
+	if(peaks == NULL){
+		puts("No memory!\n");
+		error++;
+		goto exit;
+	}
+	ofd = psf_sndCreate(argv[ARG_OUTFILE],&outprops,0,0,PSF_CREATE_RDWR);
+	if(ofd < 0){
+		printf("Error: unable to create outfile %s\n",argv[ARG_OUTFILE]);
+		error++;
+		goto exit;
+	}
+	
+    halfsec = inprops.srate / 2;
+	framepos = 0;
+	printf("processing....\n");									
+	
+	while ((framesread = psf_sndReadFloatFrames(ifd,inframe,1)) > 0){
+        float val;
+        for(i=0;i < nchars;i++){
+            if(orderptr[i] == NULL)
+                val = 0.0f;
+            else
+                val = *orderptr[i];
+            outframe[i] = val;
+        }
+		
+
+		if(psf_sndWriteFloatFrames(ofd,outframe,1) != 1){
+			printf("Error writing to outfile\n");
+			error++;
+			break;
+		}
+        if((framepos % halfsec) == 0){
+			printf("%.2lf secs\r",(double) framepos / (double) outprops.srate);
+            fflush(stdout);
+        }
+		framepos++;
+	}
+
+	if(framesread < 0)	{
+		printf("Error reading infile. Outfile is incomplete.\n");
+		error++;
+	}
+	printf("\n%.4lf secs\nWritten %d frames to %s\n",(double)framepos / (double) outprops.srate,framepos,argv[ARG_OUTFILE]);
+		
+	if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
+		printf("PEAK values:\n");
+		for(i=0; i < outprops.chans; i++){
+            double val, dbval;
+            val = (double) peaks[i].val;
+            if(val > 0.0){
+                dbval = 20.0 * log10(val);
+                printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+                       val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) outprops.srate);
+            }
+            else{
+                printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
+                       val,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) outprops.srate); 
+            }
+        }
+	}
+	printf("\n");
+exit:	 	
+	if(ifd >= 0)
+		psf_sndClose(ifd);
+	if(ofd >= 0)
+		psf_sndClose(ofd);
+	if(inframe)
+		free(inframe);
+    if(outframe)
+        free(outframe);
+	if(peaks)
+		free(peaks);
+
+	psf_finish();
+	return error;
+}

+ 760 - 0
dev/externals/mctools/chxformat.c

@@ -0,0 +1,760 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/* chxformat.c */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <limits.h>
+#include <portsf.h>
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+enum {ARG_PROGNAME, ARG_INFILE,ARG_NARGS};
+enum {GUID_PCM,GUID_IEEE,GUID_AMB_PCM,GUID_AMB_IEEE};
+
+char* guidnames[] = {"PCM","PCM FLOAT","AMB PCM","AMB FLOAT"};
+
+
+#define REVDWBYTES(t)	( (((t)&0xff) << 24) | (((t)&0xff00) << 8) | (((t)&0xff0000) >> 8) | (((t)>>24) & 0xff) )
+#define REVWBYTES(t)	( (((t)&0xff) << 8) | (((t)>>8) &0xff) )
+#define TAG(a,b,c,d)	( ((a)<<24) | ((b)<<16) | ((c)<<8) | (d) )
+
+#ifdef linux
+#define POS64(x) (x.__pos)
+#else
+#define POS64(x) (x)
+#endif
+
+#define WAVE_FORMAT_PCM			(0x0001)
+#define sizeof_WFMTEX  (40)
+typedef struct _GUID 
+{ 
+    unsigned int        Data1; 
+    unsigned short       Data2; 
+    unsigned short       Data3; 
+    unsigned char        Data4[8]; 
+} GUID; 
+
+
+typedef struct  {
+	WORD  wFormatTag; 
+    WORD  nChannels; 
+    DWORD nSamplesPerSec; 
+    DWORD nAvgBytesPerSec; 
+    WORD  nBlockAlign; 
+    WORD  wBitsPerSample; 
+
+} WAVEFORMAT;
+
+
+typedef struct { 
+    WORD  wFormatTag; 
+    WORD  nChannels; 
+    DWORD nSamplesPerSec; 
+    DWORD nAvgBytesPerSec; 
+    WORD  nBlockAlign; 
+    WORD  wBitsPerSample; 
+    WORD  cbSize; 
+} WAVEFORMATEX; 
+
+typedef struct {
+    WAVEFORMATEX    Format;				/* 18 bytes */
+    union {
+        WORD wValidBitsPerSample;       /* bits of precision  */
+        WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
+        WORD wReserved;                 /* If neither applies, set to */
+                                        /* zero. */
+    } Samples;
+    DWORD    dwChannelMask;				/* which channels are */
+                                        /* present in stream  */
+    GUID     SubFormat;
+} WAVEFORMATEXTENSIBLE;
+
+static const GUID  KSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010,
+								{0x80,
+								0x00,
+								0x00,
+								0xaa,
+								0x00,
+								0x38,
+								0x9b,
+								0x71}};
+
+static const GUID  KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003,0x0000,0x0010,
+								{0x80,
+								0x00,
+								0x00,
+								0xaa,
+								0x00,
+								0x38,
+								0x9b,
+								0x71}};
+
+static const GUID SUBTYPE_AMBISONIC_B_FORMAT_PCM = { 0x00000001, 0x0721, 0x11d3, 
+												{ 0x86,
+												0x44,
+												0xc8,
+												0xc1,
+												0xca,
+												0x0,
+												0x0,
+												0x0 } };
+
+
+static const GUID SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = { 0x00000003, 0x0721, 0x11d3, 
+												{ 0x86,
+												0x44,
+												0xc8,
+												0xc1,
+												0xca,
+												0x0,
+												0x0,
+												0x0 } };
+
+
+#define WAVE_FORMAT_IEEE_FLOAT	(0x0003)
+#define WAVE_FORMAT_EXTENSIBLE	(0xfffe)
+
+static int compare_guids(const GUID *gleft, const GUID *gright)
+{
+	const char *left = (const char *) gleft, *right = (const char *) gright;
+	return !memcmp(left,right,sizeof(GUID));
+}
+
+
+static int wavDoRead(FILE* fp, void* buf, DWORD nBytes)
+{
+	DWORD got = 0;	
+	if((got = fread(buf,sizeof(char),nBytes,fp)) != nBytes) {
+        return 1;
+    }
+	return 0;
+}
+
+static int byte_order()					
+{						    
+  int   one = 1;
+  char* endptr = (char *) &one;
+  return (*endptr);
+}
+
+static void fmtSwapBytes(WAVEFORMATEX  *pfmt)
+{	
+	pfmt->wFormatTag	= (WORD) REVWBYTES(pfmt->wFormatTag);
+	pfmt->nChannels		= (WORD) REVWBYTES(pfmt->nChannels);
+	pfmt->nSamplesPerSec	= REVDWBYTES(pfmt->nSamplesPerSec);
+	pfmt->nAvgBytesPerSec	= REVDWBYTES(pfmt->nAvgBytesPerSec);
+	pfmt->nBlockAlign	= (WORD) REVWBYTES(pfmt->nBlockAlign);
+	pfmt->wBitsPerSample	= (WORD) REVWBYTES(pfmt->wBitsPerSample);	
+}
+
+
+
+void printmaskinfo()
+{
+    printf("WAVEX Speaker positions:\n");
+
+    
+printf(
+"FRONT LEFT             0x1\n"
+"FRONT RIGHT            0x2\n"
+"FRONT CENTER           0x4\n"
+"LOW FREQUENCY          0x8\n"
+"BACK LEFT              0x10\n"
+"BACK RIGHT             0x20\n"
+"FRONT LEFT OF CENTER   0x40\n"
+"FRONT RIGHT OF CENTER  0x80\n"
+"BACK CENTER            0x100\n"
+"SIDE LEFT              0x200\n"
+"SIDE RIGHT             0x400\n"
+"TOP CENTER             0x800\n"
+"TOP FRONT LEFT         0x1000\n"
+"TOP FRONT CENTER       0x2000\n"
+"TOP FRONT RIGHT        0x4000\n"
+"TOP BACK LEFT          0x8000\n"
+"TOP BACK CENTER        0x10000\n"
+"TOP BACK RIGHT         0x20000\n"
+       );
+printf("The value 0x80000000 is reserved.\n");
+    
+printf("Standard layouts:\n"
+
+"Mono       0x40        (64)\n"
+"Stereo     0x03         (3)\n"
+"Quad       0x33        (51)\n"
+"LCRS       0x107      (263)\n"
+"5.0        0x37        (55)\n"
+"5.1        0x3f        (63)\n"
+"7.1        0xff       (255)\n"
+"Cube       0x2d033 (184371)\n"
+       ); 
+}
+
+void usage(void)
+{
+    printf("CDP MCTOOLS: CHXFORMAT v1.0.1beta (c) RWD,CDP 2009\n");
+    printf("change GUID and/or speaker mask in WAVEX header of infile.\n");
+    printf("usage: chxformat [-m | [[-t] [-gGUID] [-sMASK]] filename\n");
+    printf(
+           " -gGUID : change GUID type between PCM and AMB.\n"
+           "          Plain WAVEX: GUID = 1\n"
+           "          AMB:         GUID = 2\n"
+           " -sMASK : change speaker position mask.\n"
+           "          MASK = 0:  unset channel mask\n"
+           "             else set to MASK\n"
+           "          MASK may be given in decimal or hex (prefix '0x').\n"
+           " -m     : (not in combination with other options)\n"
+           " NOTE: speaker positions are only supported for WAVEX PCM files.\n"
+           "       If GUID is set to 2, the -s option should not be used. Any existing\n"
+           "       speaker positions will be set to zero.\n"
+           " Type chxformat -m to see list of WAVEX mask values.\n"
+           " -t     : Test only: do not modify file.\n"
+           "  If only infile given, program prints current GUID type and speaker mask.\n"
+           "  In test mode, program checks file, prints current channel mask as binary,\n"
+           "   and new mask in binary, if -s option set.\n"
+           "  Otherwise: program modifies infile (\"destructively\") - use with care!\n"
+           );
+    
+}
+
+void binprintf(int val,int skipzeroes)
+{
+    unsigned int nbits = sizeof(int) * CHAR_BIT;
+    unsigned int i = 0;
+    unsigned int mask = 1 << (nbits-1); /* i.e. 0x80000000; */
+    // skip leading zeroes
+    if(skipzeroes){
+        for(;i < nbits;i++){
+            if(val&mask)
+                break;
+            mask>>=1;
+        }
+    }
+    for(;i < nbits;i++){
+        if(i > 0 && i%8 == 0)
+            printf(" ");
+        printf("%d",(val & mask) ? 1 : 0);
+        mask >>= 1;
+    }
+}
+
+int countbits(int val)
+{
+    unsigned int nbits = sizeof(int) * CHAR_BIT;
+    unsigned int i = 0;
+    int count = 0;
+    unsigned int mask = 1 << (nbits-1); /* i.e. 0x80000000; */
+    for(;i< nbits;i++){
+        if(val & mask)
+            count++;
+        mask >>= 1;
+    }
+    return count;
+}
+
+int isdec(int ch){
+    if(ch >= '0' && ch <= '9')
+        return 1;
+//    printf("isdec fail: %d\n",ch);
+    return 0;
+}
+
+int ishex(int ch){
+    
+    if((ch >='A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
+        return 1;
+//     printf("ishex fail: %c\n",ch);
+    return 0;
+}
+
+int validate_mask(const char* mask)
+{
+    int is_dec = 1,is_hex = 1;
+    size_t i,len;
+    char* pch;
+    if(mask==NULL)
+        return 0;
+    len = strlen(mask);
+    if(len==0)
+        return 0;
+    
+    pch = (char*) mask;
+    /*try hex */
+    if(len > 2 && *pch =='0'){
+        pch++;
+        if(*pch=='x' || *pch =='X'){ // prefix found
+            pch++;
+//            printf("got hex prefix\n");
+            for(i = 0;i < len-2;i++){
+//                printf("testing %d \n",pch[i]);
+                if(!(isdec(pch[i]) || ishex(pch[i]))){
+                    is_hex = 0;
+                    break;
+                }
+            }
+            if(is_hex)
+                return 1;
+        }
+        // not hex, maybe decimal
+    }
+    pch = (char*) mask;
+    for(i=0;i < len;i++){
+        if(!isdec(pch[i])){
+            is_dec = 0;
+            break;
+        }
+    }
+    return is_dec;
+}
+
+
+
+int main (int argc, char**argv)
+{
+    int do_changeguid = 0;
+    int in_guidtype =0;
+    int guidtoset = 0;
+    int do_changemask = 0;
+    unsigned int speakermask = 0;
+    int fmtfound = 0;
+    int test = 0;
+    int src_is_amb = 0;
+    FILE* fp  = NULL;
+    char* maskstring = NULL;
+    psf_format outformat;
+    psf_format new_outtype;
+    DWORD tag;
+    DWORD size;
+    fpos_t bytepos;
+    DWORD fmtoffset = 0;
+    DWORD guidoffset = 0;
+    DWORD maskoffset = 0;
+	WORD cbSize;
+    WORD validbits;
+    DWORD chmask;
+    WAVEFORMATEXTENSIBLE fmt;
+    int is_little_endian = byte_order();
+    
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.0.1b\n");
+        return 0;
+    }
+    
+    if(argc<2){
+        usage();
+        return 1;
+    }
+    while(argv[1][0]=='-'){
+		switch(argv[1][1]){
+            case 'm':
+                if(argc > 2){
+                    printf("cannot use -m with other options\n");
+                    return 1;
+                }
+                else{
+                    printmaskinfo();
+                    return 0;
+                }
+                break;
+            case 'g':
+                if(do_changeguid){
+                    printf("Cannot use -g option more than once!\n");
+                    return 1;
+                }
+                guidtoset = atoi(&argv[1][2]);
+                if(guidtoset < 1 || guidtoset > 2) {
+                    printf("bad value for -g option - use 1 or 2 only.\n");
+                    return 1;
+                }
+                do_changeguid = 1;
+                break;
+            case 's':
+                if(do_changemask){
+                    printf("Cannot use -s option more than once!\n");
+                    return 1;
+                }
+                maskstring =  &argv[1][2];
+                if(validate_mask(maskstring)==0){
+                    printf("Bad format for mask argument.\n"
+                           "Value must be decimal, or hex with 0x prefix.\n");
+                    return 1;
+                }
+                    
+                do_changemask = 1;
+                break;
+            case 't':
+                if(test==1){
+                    printf("You only need to set -t once!\n");
+                }
+                else
+                    printf("Test mode: no changes will be made.\n");
+                test = 1;
+                
+                break;
+            default:
+                printf("illegal option %s\n",argv[1]);
+                return 1;
+        }
+        argc--;
+        argv++;
+    }
+    if(argc != 2){
+        printf("infile argument required.\n");
+        usage();
+        return 1;
+    }
+    psf_init();
+    /* nitty-gritty to read header */
+    outformat = psf_getFormatExt(argv[ARG_INFILE]);
+	if(!(outformat == PSF_STDWAVE|| outformat==PSF_WAVE_EX)){
+		printf("file mustbe WAVEX format with .wav or .amb extension.\n");
+        return 1;
+	}
+    
+    fp = fopen(argv[ARG_INFILE],"rb+");
+    if(fp==NULL){
+        printf("unable to open infile %s\n",argv[ARG_INFILE]);
+        return 1;
+    }
+    if(wavDoRead(fp,(char *)&tag,sizeof(DWORD))
+		|| wavDoRead(fp,(char *) &size,sizeof(DWORD))) {
+		printf("read error 1\n");
+        return 1;
+    }
+	if(!is_little_endian)
+		size = REVDWBYTES(size);
+	else
+		tag = REVDWBYTES(tag);
+	if(tag != TAG('R','I','F','F')){
+		printf("not a RIFF file\n");
+        return 1;
+    }
+	if(size < (sizeof(WAVEFORMAT) + 3 * sizeof(WORD))){
+		printf("file has bad header.\n");
+        return 1;
+    }
+
+	if(wavDoRead(fp,(char *)&tag,sizeof(DWORD))) {
+		printf("read error 2\n");
+        return 1;
+    }
+	if(is_little_endian)
+		tag = REVDWBYTES(tag);
+	if(tag != TAG('W','A','V','E')){
+		printf("Not a WAVE file.\n");
+        return 1;    
+    }
+	for(;;){
+        if(fmtfound) 
+            break;
+		if(wavDoRead(fp,(char *)&tag,sizeof(DWORD))
+				|| wavDoRead(fp,(char *) &size,sizeof(DWORD))) {
+			printf("read error 3\n");
+            return 1;
+        }
+		if(!is_little_endian)
+			size = REVDWBYTES(size);
+		else
+			tag = REVDWBYTES(tag);
+		switch(tag){
+		case(TAG('f','m','t',' ')):
+			if( size < sizeof(WAVEFORMAT)){
+				printf("file has bad format.\n");
+                return 1;
+            }
+            
+			if(size > sizeof_WFMTEX) {
+				printf("file has unsupported WAVE format.\n");
+                return 1;
+            }
+			if(fgetpos(fp,&bytepos)) {
+			    printf("seek error\n");
+                return 1;
+            }
+			fmtoffset = (DWORD) POS64(bytepos);
+			if(wavDoRead(fp,(char *) &fmt.Format,sizeof(WAVEFORMAT))){				
+				printf("read error 4\n");
+                return 1;
+			}
+			if(!is_little_endian)		
+				fmtSwapBytes(&fmt.Format);	
+			/* calling function decides if format is supported*/
+			if(size > sizeof(WAVEFORMAT)) {
+				if(wavDoRead(fp,(char*)&cbSize,sizeof(WORD))){
+					printf("read error 5\n");
+                    return 1;
+                }
+				if(!is_little_endian)		
+					cbSize = (WORD) REVWBYTES(cbSize);
+                if(cbSize==0){
+                    printf("file is plain WAVE format.\n");
+                    return 1;
+                }
+				if(fmt.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE){
+					if(cbSize != 22) {
+						printf("not a recognized WAVEX file.\n");
+                        return 1;
+					}
+				}				
+				if(wavDoRead(fp,(char *) &validbits,sizeof(WORD))){
+					printf("read error 6\n");
+                    return 1;
+                }
+                
+				if(!is_little_endian)
+                    validbits = REVWBYTES(validbits);
+                fmt.Samples.wValidBitsPerSample = (WORD) validbits;
+				if(wavDoRead(fp,(char *) &chmask,sizeof(DWORD))) {
+					printf("read error 7\n");
+                    return 1;
+                }
+				if(!is_little_endian)
+                    chmask = REVDWBYTES(chmask);
+                fmt.dwChannelMask = chmask;
+				if(wavDoRead(fp,(char *) &(fmt.SubFormat),sizeof(GUID))) {
+					printf("read error 8 \n");
+                    return 1;
+                }
+				if(!is_little_endian){
+					fmt.SubFormat.Data1 = REVDWBYTES(fmt.SubFormat.Data1);
+					fmt.SubFormat.Data2 = (WORD) REVWBYTES(fmt.SubFormat.Data2);
+					fmt.SubFormat.Data3 = (WORD) REVWBYTES(fmt.SubFormat.Data3);	
+				}
+				/* if we get a good GUID, we are ready to make changes! */
+                
+				if(compare_guids(&(fmt.SubFormat),&(KSDATAFORMAT_SUBTYPE_PCM))) {
+                    in_guidtype = GUID_PCM;
+                    if(test)
+                        printf("Current GUID: KSDATAFORMAT_SUBTYPE_PCM.\n");
+                }
+                else if(compare_guids(&(fmt.SubFormat),&(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) {
+                    in_guidtype = GUID_IEEE;
+                    if(test)
+                        printf("Current GUID: KSDATAFORMAT_SUBTYPE_IEEE_FLOAT.\n");
+                }
+                else if(compare_guids(&(fmt.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_PCM))) {
+                    in_guidtype = GUID_AMB_PCM;
+                    src_is_amb = 1;
+                    if(test)
+                        printf("Current GUID: SUBTYPE_AMBISONIC_B_FORMAT_PCM.\n");
+                }
+                else if(compare_guids(&(fmt.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT))){
+                    in_guidtype = GUID_AMB_IEEE;
+                    src_is_amb = 1;
+                    if(test)
+                        printf("Current GUID: SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT.\n");
+                }
+                else {
+                    printf("unrecognized WAVE_EX GUID.\n");
+                    return 1;
+                }				
+			}
+            else {
+                printf("WAVEX format required.\n"
+                       "Use copysfx to convert to WAVEX format.\n");
+                return 1;
+            }
+            fmtfound = 1;			
+			break;
+		case TAG('d','a','t','a'):
+            if(!fmtfound){
+                printf("bad WAVE file: no fmt chunk found!\n");
+                return 1;
+            }                 
+        default:
+			/* unknown chunk - skip */
+            if(!fmtfound) {
+                if(fseek(fp,size,SEEK_CUR)){
+                    printf("seek error\n");
+                    return 1;
+                }
+            }
+			break;
+		}
+	}
+    if(!fmtfound){
+         printf("no fmt chunk found!\n");
+         return 1;
+    }
+    
+    maskoffset = fmtoffset + sizeof(WAVEFORMAT) + sizeof(WORD)*2;
+    guidoffset = maskoffset + sizeof(DWORD);
+    
+    if(!(do_changeguid || do_changemask)){
+        /* display what we know */
+        printf("Wordsize     : %d\n",validbits);
+        printf("Channels     : %d\n",fmt.Format.nChannels);
+        printf("GUID         : %s\n",guidnames[in_guidtype]);
+        if(chmask==0)
+            printf("Channel mask : 0\n");
+        else
+            printf("Channel mask : 0x%06x (%d)\n",(unsigned int) chmask,(int) chmask);
+        if(chmask){
+            printf("Channel mask (binary): ");
+            binprintf(chmask,1);
+            printf("There are %d speaker positions set.\n",countbits(chmask));
+            
+        }
+        printf("\n");
+    }
+    else {
+        int bits,is_same = 0;
+
+        /* check all settings before making any changes */
+        if(do_changemask){
+            // be strict!
+            if(src_is_amb && guidtoset != 1){
+                printf("-s flag only supported for PCM files (AMB speaker mask must be zero).\n"
+                       "Exiting.\n");
+                return 1;
+            }
+            if(strncmp(maskstring,"0x",2)==0)
+                sscanf(maskstring,"%x", &speakermask);
+            else
+                sscanf(maskstring,"%u", &speakermask);
+            bits = countbits(speakermask);
+            /* can't do much if a silly huge value given */
+            if(speakermask < 0 || speakermask >= 0x40000){
+                printf("Mask value out of range!\n");
+                return 1;
+            }
+            if(bits > fmt.Format.nChannels){
+                printf("Error: %d positions requested for %d channels: \n",bits,fmt.Format.nChannels);
+                binprintf(speakermask,1);
+                printf("\n");
+                return 1;
+            }
+            if(bits && bits < fmt.Format.nChannels){
+                printf("Warning: %d requested positions less than channels in file.\n",bits);
+            }
+        }
+                
+        if(do_changeguid){
+            GUID nuguid;
+            
+            // set float or pcm GUID as required.
+            // no copy to same: only convert if types are different
+            switch(guidtoset){
+            case 1:       // plain wavex - the easy iption
+                if(in_guidtype == GUID_AMB_PCM){
+                    nuguid = KSDATAFORMAT_SUBTYPE_PCM;
+                }
+                else if(in_guidtype == GUID_AMB_IEEE) {
+                    nuguid = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+                }
+                else
+                    is_same = 1;
+                new_outtype = PSF_STDWAVE;
+                break;
+            case 2:  // convert to amb - must zero speaker flags
+                if(in_guidtype == GUID_PCM)
+                    nuguid = SUBTYPE_AMBISONIC_B_FORMAT_PCM;
+                else if(in_guidtype == GUID_IEEE)
+                    nuguid = SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT;
+                else
+                    is_same = 1;
+                // set mask to zero if setting AMB format
+                if(is_same==0) {
+                    do_changemask = 1;
+                    maskstring = "0";
+                    speakermask = 0;
+                }
+                new_outtype = PSF_WAVE_EX;    
+                break;
+            }
+            if(is_same){
+                printf("new GUID identical - no change made.\n");
+            }
+            else {
+                int err;
+                //make the change!
+                if(!is_little_endian){
+                    nuguid.Data1 = REVDWBYTES(nuguid.Data1);
+					nuguid.Data2 = (WORD) REVWBYTES(nuguid.Data2);
+					nuguid.Data3 = (WORD) REVWBYTES(nuguid.Data3);
+                }
+                if(!test){
+                    if(fseek(fp,guidoffset,SEEK_SET) !=0){
+                        printf("seek error updating channelmask. exiting.\n");
+                        return 1;
+                    }
+                    err = fwrite((char*) &nuguid,1,sizeof(GUID),fp);
+                    if(err != sizeof(GUID)){
+                        printf("Error updating GUID. File may have inconsistent header.\n");
+                        return 1;
+                    }
+                    printf("new GUID set.\n");
+                    
+                }
+            }
+            
+        }
+        if(do_changemask){
+            /* read user mask value */
+            /* TODO: full parse, trap bad characters */
+            if(chmask==speakermask){
+                if(speakermask > 0)
+                    printf("Requested mask is already set. Data not modified.\n");
+            }
+            else {
+                DWORD writemask;
+                int err;
+                
+                if(speakermask > 0){
+                    printf("new mask = %d (",speakermask);
+                    binprintf(speakermask,1);
+                    printf(")\n");
+                }
+                if(fseek(fp,maskoffset,SEEK_SET) !=0){
+                    printf("seek error updating channelmask. exiting.\n");
+                    return 1;
+                }
+                writemask = speakermask;
+                if(!is_little_endian)
+                    writemask = REVDWBYTES(speakermask);
+                if(!test){
+                    err = fwrite((char*) &writemask,1,sizeof(DWORD),fp);
+                    if(err != sizeof(DWORD)){
+                        printf("Error updating mask. File may have inconsistent header.\n");
+                        return 1;
+                    }
+                    printf("New mask set.\n");
+                }
+            }
+                
+        }
+        if(outformat == PSF_STDWAVE && new_outtype==PSF_WAVE_EX)
+            printf("File extension should be changed to amb.\n");
+        else if(outformat == PSF_WAVE_EX && new_outtype == PSF_STDWAVE)
+            printf("File extension should be changed to wav.\n");
+    }
+    fseek(fp,0,SEEK_END);
+    fclose(fp);
+    return 0;
+}
+
+
+    

+ 604 - 0
dev/externals/mctools/copysf.c

@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/*
+ *	copysfx: version of copysfx using portsf
+ */
+/* Oct 2009: added cube */
+/* Dec 2009 1.9.1. fixed horrible bug failing to convert to WAVE_EX! */
+/* March 2012 corrected wave type arg parsing  */
+/* August 2012 updated portsf to correct SPKRS_MONO */
+/* Nov 2013 added MC_SURR_6_1 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef _WIN32
+#include <malloc.h>			//RWD.6.5.99
+#endif
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <portsf.h>
+
+#define VERSION "Revision: 2.1.1 2020 "
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+enum {OPT_STD_WAVE,OPT_WAVEX_GENERIC,OPT_WAVEX,OPT_WAVEX_LCRS,OPT_WAVEX_SURROUND,OPT_WAVEX_BFORMAT,OPT_WAVEX_5_0,OPT_WAVEX_7_1,OPT_WAVEX_CUBE,OPT_WAVEX_6_1,};
+/*
+The number of channels defines the order of the soundfield:
+ 3 channel = h   = 1st order horizontal
+ 4 channel = f   = 1st order 3-D
+ 5 channel = hh  = 2nd order horizontal
+ 6 channel = fh  = 2nd order horizontal + 1st order height (formerly
+called 2.5 order)
+ 7 channel = hhh = 3rd order horizontal
+ 8 channel = fhh = 3rd order horizontal + 1st order height
+ 9 channel = ff  = 2nd order 3-D
+11 channel = ffh = 3rd order horizontal + 2nd order height
+16 channel = fff = 3rd order 3-D
+*/
+#define N_BFORMATS (10)
+static const int bformats[N_BFORMATS] = {2,3,4,5,6,7,8,9,11,16};
+
+int get_sampsize(psf_stype type)
+{
+    int size = 0;
+    switch(type){
+		case PSF_SAMP_8:
+			size = 1;
+			break;
+		case PSF_SAMP_16:
+			size = 2;
+			break;
+		case PSF_SAMP_24:
+			size = 3;
+			break;
+		case PSF_SAMP_32:
+		case PSF_SAMP_IEEE_FLOAT:
+			size = 4;
+			break;
+		default:
+			break;
+    }
+    return size;
+}
+
+
+
+void
+usage()
+{
+	fprintf(stderr,"\n\nCDP MCTOOLS: COPYSFX  (c) RWD,CDP %s\n",VERSION);
+	fprintf(stderr,"\tcopy/convert soundfiles\n");
+	fprintf(stderr,"usage: copysfx [-d][-h][-sN] [-tN] infile outfile\n");
+	fprintf(stderr,"-d   : apply TPDF dither to 16bit outfile.\n"
+                   "-s   : force output sample type to type N.\n");
+	fprintf(stderr,"      Available sample types:\n"
+                   "      1  : 16bit integers (shorts)\n"
+                   "      2  : 32bit integer  (longs)\n"
+                   "      3  : 32bit floating-point\n"
+                   "      4  : 24bit integer 'packed' \n"
+                   "      Default: format of infile.\n");
+				   
+	fprintf(stderr,"-h   : write mimimum header (no extra data).\n"
+				   "       Default: include PEAK data.\n"
+            );
+/*	fprintf(stderr,"-i   : interpret 32bit files as floats (use with care!)\n"); */
+	fprintf(stderr,"-tN  : write outfile format as type N\n");
+	fprintf(stderr,"Possible formats:\n"
+					"0   : standard soundfile (.wav, .aif, .afc, .aifc)\n"
+					"1   : generic WAVE_EX (no speaker assignments)\n"
+					"2   : WAVE_EX mono/stereo/quad(LF,RF,LR,RR) - infile nchans must match\n"
+					"3   : WAVE_EX quad surround (L,C,R,S)       - infile must be quad\n"
+					"4   : WAVE_EX 5.1 format surround           - infile must be 6-channel\n"
+					"5   : WAVE_EX Ambisonic B-format (W,X,Y,Z...) - file extension .amb supported \n"
+                    "6   : WAVE_EX 5.0 Surround                  - infile must be 5-channel\n"
+                    "7   : WAVE_EX 7.1 Surround                  - infile must be 8-channel\n"
+                    "8   : WAVE_EX Cube Surround                 - infile must be 8-channel\n"
+                    "9   : WAVE_EX 6.1 Surround  (new in v2.1.0) - infile must be 7-channel\n"
+					"default in all cases: outfile has format of infile\n"
+					"NB: types 1 to 9 are for WAV format only\n"
+                    "See also CHXFORMAT: destructively change WAVE_EX GUID and/or speaker mask.\n"
+					);	
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+	unsigned long size,i;
+	unsigned long channels,srate;
+	//RWD.6.5.99
+	PSF_PROPS  inprops,outprops; 
+	int force_wave = 0,rc = 0;
+    psf_stype force_stype = 0;
+	int opt_wave_type = -1;
+	int min_header = 0;
+	int interpret_floats = 0;
+	int res;	
+	char *create_msg = NULL;
+    int do_dither = 0;
+    psf_format  outformat = PSF_FMT_UNKNOWN;
+	unsigned long update_size;
+	PSF_CHPEAK  *peaks = NULL;
+	MYLONG peaktime;
+	char* ext = NULL;
+	int have_amb_ext = 0;
+    int ifd;		/* the input file */
+    int ofd;		/* the output file */
+    float *sampleframe = NULL;
+	double outsize_bytes;
+	double maxsize = pow(2.0,32.0) - 200.0;  /* some safety margin! */
+	
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("2.0.3\n");
+        return 0;
+    }
+
+	if(psf_init()) {		
+		printf("failed to init psfsys\n");
+		exit(1);
+	}
+
+	if(argc < 3){
+		usage();
+		exit(1);
+	}
+
+	printf("\nCDP MCTOOLS: COPYSFX v2.0.3 (c) RWD,CDP 2011\n");
+
+	while(argv[1][0]=='-'){
+		int sflag = 0;
+		switch(argv[1][1]){
+        case 'd':
+            do_dither = 1;
+            break;
+		case('t'):
+			if(argv[1][2]=='\0'){
+				fprintf(stderr,"-t flag requires parameter\n");
+				usage();
+				exit(1);
+			}
+			opt_wave_type = atoi(&(argv[1][2]));
+			if((opt_wave_type < 0) || opt_wave_type > OPT_WAVEX_CUBE){
+				fprintf(stderr,"wave type out of range\n");
+				usage();
+				exit(1);
+			}
+			force_wave = 1;
+			break;		
+		case('s'):
+			if(argv[1][2]=='\0'){
+				fprintf(stderr,"-s flag requires parameter\n");
+				usage();
+				exit(1);
+			}
+			if(force_stype >0){
+				fprintf(stderr,"copysfx: error: -s flag may only be used once!\n");
+				usage();
+				exit(1);
+			}
+			sflag = atoi(&(argv[1][2]));
+			if(sflag < 1 || sflag > 6){
+				fprintf(stderr,"-s parameter out of range\n");
+				usage();
+				exit(1);
+			}
+			switch(sflag){
+			case(1):
+				force_stype = PSF_SAMP_16;
+				break;
+			case(2):
+				force_stype = PSF_SAMP_32;
+				break;
+			case(3):
+				force_stype = PSF_SAMP_IEEE_FLOAT;
+				break;
+			case(4):
+				force_stype = PSF_SAMP_24;
+				break;			
+			default:
+				fprintf(stderr,"internal error: unmatched sampletype parameter!\n");
+				break;
+			}
+			break;
+		case('h'):
+            min_header = 1;    
+			break;
+#ifdef NOTDEF
+		case('i'):
+			interpret_floats = 1;
+			break;
+#endif
+		default:
+			fprintf(stderr,"unknown flag option %s\n",argv[1]);
+			usage();
+			exit(1);
+			
+		}
+		argc--; argv++;
+	}
+
+	if(argc < 3){
+		usage();
+		exit(1);
+	}
+
+	if((ifd = psf_sndOpen(argv[1],&inprops,0)) < 0) {
+		fprintf(stderr, "copysfx: can't open input SFfile %s:\n\t",
+				argv[1]);
+		exit(1);
+	}
+		
+	size = psf_sndSize(ifd);
+	channels = inprops.chans;
+	sampleframe = (float *) malloc(channels * sizeof(float));
+	if(sampleframe==NULL){
+		psf_sndClose(ifd);
+		puts("no memory for sample buffer\n");
+		exit(1);
+	}
+	
+	srate = inprops.srate;
+	update_size = (unsigned long)((double)srate * 0.5);
+	outprops = inprops;
+	/* if -i flag used, infile is floats, therefore we write outfile as floats,
+	 * UNLESS we also have outtype coercion!
+	 */
+	if(interpret_floats)
+		outprops.samptype = PSF_SAMP_IEEE_FLOAT;
+
+	if(inprops.format== PSF_WAVE_EX){		
+		printf("opened WAVE-EX file:\n");
+		switch(inprops.chformat){
+		
+		case(MC_STD):
+			printf("\tno speaker assignments defined\n");		
+			break;
+		case(MC_MONO):
+			printf("\tMONO\n");
+			break;
+		case(MC_STEREO):
+			printf("\tSTEREO\n");
+			break;		
+		case(MC_QUAD):
+			printf("\tGeneric quad format: LF-RF-LR-RR\n");			
+			break;
+		case(MC_LCRS):
+			printf("\tQuad Surround: L-C-R-S format\n");			
+			break;
+		case(MC_BFMT):
+			printf("\tAmbisonic B-Format\n");
+			break;
+		case(MC_DOLBY_5_1):
+			printf("\t5.1 surround\n");
+			break;
+        case(MC_SURR_5_0):
+			printf("\t5.0 surround\n");
+			break;
+		case(MC_SURR_6_1):
+            printf("\t6.1 Surround\n");
+            break;
+        case(MC_SURR_7_1):
+            printf("\t7.1 Surround\n");
+            break;
+        case(MC_CUBE):
+            printf("\tCube Surround\n");
+            break;
+		default:
+			printf("\tunrecognized speaker positions\n");
+			break;						
+		}
+		if(min_header==1)
+			printf("WARNING: minimum header is not recommended for WAVE_EX files\n");
+	}
+
+	peaks = (PSF_CHPEAK *) calloc(channels,sizeof(PSF_CHPEAK));
+	if(peaks==NULL){
+		puts("no memory for fpeak data buffer\n");
+		psf_sndClose(ifd);
+		exit(1);
+	}
+
+	//read infile peak data, if it exists, and report to user	
+	res = psf_sndReadPeaks(ifd,peaks,  &peaktime);
+	if(res ==0)	{
+		printf("no peak data in this infile\n");
+	}
+	else if(res < 0){
+		fprintf(stderr,"error reading infile peak data\n");
+		psf_sndClose(ifd);
+		exit(1);
+	}
+	else {
+		time_t t_peaktime = (time_t) peaktime;
+		printf("Infile PEAK data:\n\tcreation time: %s\n", ctime(&t_peaktime));
+		for(i=0;i < channels; i++)
+#ifdef CPLONG64
+			printf("CH %ld: %.4lf at frame %u:\t%.4lf secs\n",
+#else
+            printf("(32) CH %ld: %.4lf at frame %lu:\t%.4lf secs\n",
+#endif
+				i,peaks[i].val,peaks[i].pos,(double) (peaks[i].pos) / (double)srate);
+	}
+	
+	if(force_stype > PSF_SAMP_UNKNOWN)		
+		outprops.samptype = force_stype;
+
+	outsize_bytes = (double) size * outprops.chans * get_sampsize(outprops.samptype);
+    if(outsize_bytes > maxsize){
+        printf("output file size %.0f MB exceeds 4GB: cannot proceed.\n",outsize_bytes / 1048576.0);
+        exit(1);
+    }
+	
+	if(force_wave){
+		int i,matched;
+		//check file extension...
+		switch(opt_wave_type){
+		case(OPT_STD_WAVE):
+			outprops.chformat = STDWAVE;
+			outprops.format = PSF_STDWAVE;
+			create_msg = "creating standard WAVE file\n";
+			break;
+		case(OPT_WAVEX_GENERIC):
+			inprops.chformat = MC_STD;
+			outprops.format = PSF_WAVE_EX;
+			create_msg = "creating STD WAVE_EX file\n";
+			break;
+		case(OPT_WAVEX):
+			switch(inprops.chans){
+			case(1):
+				outprops.chformat = MC_MONO;				
+				outprops.format = PSF_WAVE_EX;
+				create_msg = "creating MONO WAVE_EX file\n";
+				break;
+			case(2):
+				outprops.chformat = MC_STEREO;				
+				outprops.format = PSF_WAVE_EX;
+				create_msg = "creating STEREO WAVE_EX file\n";
+				break;
+			case(4):
+				outprops.chformat = MC_QUAD;			
+				outprops.format = PSF_WAVE_EX;
+				create_msg = "creating QUAD WAVE_EX file\n";
+				break;
+			default:
+				fprintf(stderr,"infile nchans incompatible with requested WAVE-EX format\n");
+				usage();
+				psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);
+				exit(1);				
+			}
+			break;
+		case(OPT_WAVEX_LCRS):
+			if(inprops.chans != 4){
+				fprintf(stderr,"infile must have four channels\n");
+				usage();
+				psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);
+				exit(1);
+			}
+			outprops.chformat = MC_LCRS;
+			outprops.format = PSF_WAVE_EX;
+			create_msg = "creating LCRS-surround WAVE_EX file\n";
+			break;
+		case(OPT_WAVEX_SURROUND):
+			if(inprops.chans != 6){
+				fprintf(stderr,"infile must have six channels\n");
+				usage();
+				psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);
+				exit(1);
+			}
+			outprops.chformat = MC_DOLBY_5_1;			
+			outprops.format = PSF_WAVE_EX;
+			create_msg = "creating 5.1 surround WAVE_EX file\n";
+			break;			
+		case(OPT_WAVEX_BFORMAT):
+			matched = 0;
+			for(i=0;i < N_BFORMATS;i++)	{
+				if(inprops.chans == bformats[i]){
+					matched = 1;
+					break;
+				}
+			}
+			if(!matched){
+				printf("WARNING: No Bformat definition for %d-channel file.\n",inprops.chans);
+			}
+			outprops.chformat = MC_BFMT;			
+			outprops.format = inprops.format = PSF_WAVE_EX;
+			create_msg = "creating AMBISONIC B-FORMAT WAVE_EX file\n";
+			break;
+        case(OPT_WAVEX_5_0):
+            if(inprops.chans != 5){
+				fprintf(stderr,"infile must have five channels\n");
+				usage();
+				psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);
+				exit(1);
+			}
+			outprops.chformat = MC_SURR_5_0;			
+			outprops.format = PSF_WAVE_EX;
+			create_msg = "creating 5.0 surround WAVE_EX file\n";
+			break;
+				
+        case(OPT_WAVEX_7_1):
+            if(inprops.chans != 8){
+				fprintf(stderr,"infile must have eight channels\n");
+				usage();
+				psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);
+				exit(1);
+			}
+			outprops.chformat = MC_SURR_7_1;			
+			outprops.format = PSF_WAVE_EX;
+			create_msg = "creating 7.1 surround WAVE_EX file\n";
+			break;
+        case OPT_WAVEX_CUBE:
+            if(inprops.chans != 8){
+				fprintf(stderr,"infile must have eight channels\n");
+				usage();
+				psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);
+				exit(1);
+			}
+			outprops.chformat = MC_CUBE;			
+			outprops.format = PSF_WAVE_EX;
+			create_msg = "creating 5.0 surround WAVE_EX file\n";
+			break;			
+        case(OPT_WAVEX_6_1):
+            if(inprops.chans != 7){
+				fprintf(stderr,"infile must have seven channels\n");
+				usage();
+				psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);
+				exit(1);
+			}
+			outprops.chformat = MC_SURR_6_1;			
+			outprops.format = PSF_WAVE_EX;
+			create_msg = "creating 6.1 surround WAVE_EX file\n";
+			break;	    
+		default:
+			 printf("copysfx: Program error: impossible wave_ex type\n");
+			 psf_sndClose(ifd);
+				if(peaks)
+					free(peaks);				
+			 exit(1);
+			 
+		}
+	}
+	//ignore all that if user wants aiff!
+	//informat = inprops.format;
+	ext = strrchr(argv[2],'.');
+	if(ext && stricmp(ext,".amb")==0)
+		have_amb_ext = 1;
+
+	if(have_amb_ext){
+		if(!(outprops.format == PSF_WAVE_EX && outprops.chformat == MC_BFMT)){
+			fprintf(stderr,"Error: .amb extension only allowed for WAVE_EX B-Format file.\n");
+			exit(1);			
+		} 
+	}
+    outformat  = psf_getFormatExt(argv[2]);
+
+	if((ofd = psf_sndCreate(argv[2],&outprops,0,min_header,PSF_CREATE_RDWR)) < 0){	
+		fprintf(stderr, "copysfx: can't create output file %s:\n\t",argv[2]);		
+		psf_sndClose(ifd);
+		fprintf(stderr,"\n");
+		if(peaks)
+			free(peaks);				
+		exit(1);
+	}
+    if(do_dither)
+        psf_sndSetDither(ofd,PSF_DITHER_TPDF);
+
+	if(force_wave){
+		if(outprops.format==PSF_WAVE_EX){
+			if(outformat > PSF_WAVE_EX)
+                printf("WARNING: extended formats require .wav file format:\n\t - creating standard file\n");		
+			else
+			    printf("%s\n",create_msg);	
+		}
+	}	
+	printf("copying...\n");    
+    for(i=0;i < size;i++){
+        /* salve to CEP users: need interpret_floats somewhere...? */
+        if((psf_sndReadFloatFrames(ifd, sampleframe, 1)) != 1){
+            
+            fprintf(stderr,"copysfx: error reading from infile\n");
+            psf_sndClose(ifd);
+            psf_sndClose(ofd);
+            free(sampleframe);
+            if(peaks)
+                free(peaks);
+            exit(1);
+        }
+        if(psf_sndWriteFloatFrames(ofd, sampleframe,1)!=1){
+            fprintf(stderr,"copysfx: error writing to outfile\n");
+            psf_sndClose(ifd);
+            psf_sndClose(ofd);
+            free(sampleframe);
+            if(peaks)
+                free(peaks);
+            exit(1);			
+        }
+        if((i / channels) % update_size == 0) {	 
+            printf("%.2lf secs\r",(double) (i / channels) / (double) srate);
+            fflush(stdout);
+        }
+    }
+    printf("%.4lf secs\r",(double) (i / channels) / (double) srate);
+    	
+	if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
+		printf("Outfile PEAK values:\n");
+		for(i=0; i < (unsigned long) inprops.chans; i++){
+            double val, dbval;
+            val = (double) peaks[i].val;
+            if(val > 0.0){
+                dbval = 20.0 * log10(val);
+#ifdef CPLONG64
+                printf("CH %ld: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+#else
+                printf("CH %ld: %.6f (%.2lfdB) at frame %lu:\t%.4f secs\n",i,
+#endif
+                       val,dbval,peaks[i].pos,(double)peaks[i].pos / (double) inprops.srate);
+            }
+            else{
+#ifdef CPLONG64
+                printf("CH %ld: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
+#else        
+                printf("CH %ld: %.6f (-infdB) at frame %lu:\t%.4f secs\n",i,
+#endif
+                       val,peaks[i].pos,(double)peaks[i].pos / (double) inprops.srate); 
+            }
+        }
+	}
+	if(psf_sndClose(ifd) < 0) {		
+		rc++;
+	}
+
+	if(psf_sndClose(ofd) < 0) {		
+		rc++;
+	}
+    if(sampleframe)
+		free(sampleframe);
+	if(peaks)
+		free(peaks);	
+	psf_finish();
+	return rc;
+}
+
+
+

+ 400 - 0
dev/externals/mctools/fmdcode.c

@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+//fmdcode.c  : decode .amb file to various speaker layouts
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <portsf.h>
+#include "fmdcode.h"
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+/*
+ Channel order is WXYZ,RSTUV,KLMNOPQ
+ 
+ The number of channels defines the order of the soundfield:
+ 2 channel = W+Y =  "Mid-Side" 
+ 3 channel = h   = 1st order horizontal
+ 4 channel = f   = 1st order 3-D
+ 5 channel = hh  = 2nd order horizontal
+ 6 channel = fh  = 2nd order horizontal + 1st order height (formerly
+                                                            called 2.5 order)
+ 7 channel = hhh = 3rd order horizontal
+ 8 channel = fhh = 3rd order horizontal + 1st order height
+ 9 channel = ff  = 2nd order 3-D
+ 11 channel = ffh = 3rd order horizontal + 2nd order height
+ 16 channel = fff = 3rd order 3-D
+ 
+ 
+ Horizontal   Height  Soundfield   Number of    Channels
+ order 	      order 	  type      channels 	
+ 1 	         0 	       horizontal 	  3 	    WXY
+ 1 	         1 	      full-sphere 	  4 	    WXYZ
+ 2 	         0 	       horizontal 	  5 	    WXY....UV
+ 2 	         1 	       mixed-order    6 	    WXYZ...UV
+ 2 	         2 	      full-sphere     9 	    WXYZRSTUV
+ 3           0 	       horizontal 	  7 	    WXY....UV.....PQ
+ 3 	         1         mixed-order 	  8 	    WXYZ...UV.....PQ
+ 3 	         2 	       mixed-order 	 11 	    WXYZRSTUV.....PQ
+ 3 	         3 	      full-sphere 	 16 	    WXYZRSTUVKLMNOPQ
+
+ */
+
+
+enum {ARG_PROGNAME, ARG_INFILE,ARG_OUTFILE, ARG_LAYOUT,ARG_NARGS};
+#define N_BFORMATS (10)
+enum {FM_MONO,FM_STEREO,FM_SQUARE,FM_QUAD,FM_PENT,DM_5_0,DM_5_1,FM_HEX,FM_OCT1,FM_OCT2,FM_CUBE,FM_QUADCUBE,FM_NLAYOUTS};
+
+
+//static const int bformats[N_BFORMATS] = {2,3,4,5,6,7,8,9,11,16};
+static const int layout_chans[] = {1,2,4,4,5,5,6,6,8,8,8,8};
+
+void usage(void)
+{
+   printf(
+    "usage: fmdcode [-x][-w] infile outfile layout\n"
+	"       -w    :   write plain WAVE outfile format\n"
+    "                (.wav default - use generic wavex format).\n"
+    "       -x    : write std WAVEX speaker positions to header\n"
+    "               (applies to compatible layouts only; requires .wav extension).\n"
+	"   layout    : one of the choices below.\n"
+    "       Output channel order is anticlockwise from centre front\n"
+    "            except where indicated.\n"
+    "   Layouts indicated with * are compatible with WAVEX speaker position order. \n"
+    "   Available speaker layouts:\n"
+    "   1    :  *  mono (= W signal only)\n"
+    "   2    :  *  stereo (quasi mid/side, = W +- Y)\n"
+    "   3    :     square\n"
+    "   4    :  *  quad FL,FR,RL,RR order\n"
+    "   5    :     pentagon\n"
+    "   6    :  *  5.0 surround (WAVEX order)\n"
+    "   7    :  *  5.1 surround (WAVEX order, silent LFE)\n"
+    "   8    :     hexagon\n"
+    "   9    :     octagon 1 (front pair, 45deg)\n"
+    "   10   :     octagon 2 (front centre speaker)\n"
+    "   11   :     cube (as 3, low-high interleaved. Csound-compatible.)\n"
+    "   12   :  *  cube (as 4, low quad followed by high quad).\n"
+    " NOTE: no shelf filters or NF compensation used.\n");
+}
+
+int main(int argc,char *argv[])
+{
+	int i,ifd, ofd;
+	int layout,inorder = 1;
+    int got,halfsec;
+	unsigned int framepos;
+    int inchans,outchans;
+    int outsize;
+    int write_speakerpositions = 0;
+    MYLONG peaktime;
+    psf_channelformat chformat = MC_STD;
+    psf_format  outformat;
+	char *sfname;
+    float *frame = NULL;
+    fmhcopyfunc copyfunc;
+    fmhdecodefunc decodefunc = NULL;
+	int write_wavex = 1;
+	ABFSAMPLE abfsample;
+	PSF_PROPS props;
+	PSF_CHPEAK *peaks = NULL;
+	float abfframe[16];
+
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.0b\n");
+        return 0;
+    }
+    
+	if(argc < 3){
+		printf("\nCDP MCTOOLS: FMDCODE v 1.0beta: RWD,CDP 2009\n"
+				"Plain multi-layout decoder for .amb files.\n"
+                "Regular layouts use standard Furse-Malham in-phase coefficients.\n" 
+                "5.x surround coefficients (maxre) from David Moore.\n");
+        usage();
+		return 1;
+	}
+	while(argv[1][0] =='-'){		
+		switch(argv[1][1]){
+		case('w'):
+			write_wavex = 0;
+			break;
+        case 'x':
+            write_speakerpositions = 1;
+            break;
+		default:
+			fprintf(stderr,"fmdcode: error: illegal flag option %s\n",argv[1]);
+			return 1;
+		}
+		argc--; argv++;
+	}
+	if(argc < ARG_NARGS){
+        
+		usage();
+		return 1;
+	}
+	if(psf_init()) {		
+		printf("failed to init psfsys\n");
+		exit(1);
+	}
+	
+	sfname = argv[ARG_OUTFILE];
+	layout = atoi(argv[ARG_LAYOUT]);
+    if(layout < 1 || layout > FM_NLAYOUTS+1){
+        printf("Unsupported layout type.\n");
+        return 1;
+    }
+    
+    
+	ifd = psf_sndOpen(argv[ARG_INFILE],&props,0);
+	if(ifd < 0){
+		fprintf(stderr,"unable toopen infile %s\n",argv[ARG_INFILE]);
+		return 1;
+	}
+    inchans = props.chans;
+    if(inchans > 4) {
+        inorder = 2;
+        printf("%d-channel input: performing 2nd-order decode.\n",inchans);
+    }
+    outsize = psf_sndSize(ifd);
+	if(outsize <= 0){
+		fprintf(stderr,"fmdcode: infile is empty!\n");
+		psf_sndClose(ifd);
+		return 1;
+	}
+    
+    switch(inchans){
+	case 3:
+        copyfunc = fmhcopy_3;
+        break;
+    case 4:
+        copyfunc = fmhcopy_4;       
+        break;
+    case 5:
+        copyfunc = fmhcopy_5;
+        break;
+    case 6:
+        copyfunc = fmhcopy_6;
+        break;
+    case 7:
+        copyfunc = fmhcopy_7;
+        break;
+    case 8:
+        copyfunc = fmhcopy_8;
+        break;
+    case 9:
+        copyfunc = fmhcopy_9;
+        break;
+    case 11:
+        copyfunc = fmhcopy_11;
+        break;
+    case 16:
+        copyfunc = fmhcopy_16;
+        break;
+    default:
+        printf("file has unsupported number of channels (%d)\n",inchans);
+        psf_sndClose(ifd);
+        return 1;
+	}
+    //FM_MONO,FM_STEREO,FM_SQUARE,FM_PENT,FM_SURR,FM_SURR6,FM_HEX,FM_OCT1,FM_OCT2,FM_CUBE
+    switch(layout-1){
+        case FM_MONO:
+            printf("Decoding to Mono\n");
+            decodefunc = fm_i1_mono;
+            if(write_wavex && write_speakerpositions)
+                chformat = MC_MONO;
+            break;
+        case FM_STEREO:
+            printf("Decoding to Stereo\n");
+            decodefunc = fm_i1_stereo;
+            if(write_wavex && write_speakerpositions)
+                chformat = MC_STEREO;
+            break;
+        case FM_SQUARE:
+            printf("Decoding to Square\n");
+            if(inorder == 1)
+               decodefunc = fm_i1_square;
+            else
+               decodefunc = fm_i2_square; 
+            break;
+        case FM_QUAD:
+            printf("Decoding to quad surround (WAVEX order)\n");
+            if(inorder == 1)
+                decodefunc = fm_i1_quad;
+            else
+                decodefunc = fm_i2_quad;
+            if(write_wavex && write_speakerpositions)
+                chformat = MC_QUAD;
+            break;
+        case FM_PENT:
+            printf("Decoding to pentagon\n");
+            if(inorder==1)
+                decodefunc = fm_i1_pent;
+            else
+                decodefunc = fm_i2_pent;
+            break;
+
+        case DM_5_0:
+            printf("Decoding to 5.0 surround (David Moore)\n");
+            if(inorder==1)
+                decodefunc = dm_i1_surr;
+            else
+                decodefunc = dm_i2_surr;
+            if(write_wavex && write_speakerpositions)
+                chformat = MC_SURR_5_0;
+            break;
+        case DM_5_1:
+            printf("Decoding to  5.1 surround (David Moore)\n");
+            if(inorder==1)
+                decodefunc = dm_i1_surr6;
+            else
+                decodefunc = dm_i2_surr6;
+            if(write_wavex && write_speakerpositions)
+                chformat = MC_DOLBY_5_1;
+            break;
+        case FM_HEX:
+            printf("Decoding to Hexagon\n");
+            if(inorder==1)
+                decodefunc = fm_i1_hex;
+            else
+                decodefunc = fm_i2_hex;
+            break;
+        case FM_OCT1:
+            printf("Decoding to Octagon 1\n");
+            if(inorder==1)
+                decodefunc = fm_i1_oct1;
+            else
+                decodefunc = fm_i2_oct1;
+            break;
+        case FM_OCT2:
+            printf("Decoding to Octagon 2\n");
+            if(inorder==1)
+                decodefunc = fm_i1_oct2;
+            else
+                decodefunc = fm_i2_oct2;
+            break;
+        case FM_CUBE:
+            printf("Decoding to Cube (FM interleaved)\n");
+            if(inorder==1)
+                decodefunc = fm_i1_cube;
+            else
+                decodefunc = fm_i2_cube;
+            break; 
+        case FM_QUADCUBE:
+            printf("Decoding to Octagon 1 (WAVEX order)\n");
+            if(inorder==1)
+                decodefunc = fm_i1_cubex;
+            else
+                decodefunc = fm_i2_cubex;
+            if(write_wavex && write_speakerpositions)
+                chformat = MC_CUBE;
+            break;
+    }
+    outformat = psf_getFormatExt(sfname);
+    if(outformat >= PSF_AIFF){
+        if(write_speakerpositions)
+            printf("Warning: -x requires .wav format\n");
+    }
+    outchans = layout_chans[layout-1];
+    frame = malloc(sizeof(float) * outchans);
+    if(frame==NULL){
+        puts("No Memory!\n");
+        return 1;
+    }
+	props.chformat = STDWAVE;
+	props.chans = outchans;
+    if(!is_legalsize(outsize,&props)){
+        fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
+        return 1;
+    }
+    
+    /*TODO: set speaker pos when we can */
+	if(write_wavex){
+		props.chformat = chformat;
+		props.format = PSF_WAVE_EX;
+	}
+
+	ofd = psf_sndCreate(sfname,&props,0,0,PSF_CREATE_RDWR);
+	if(ofd < 0){
+		fprintf(stderr,"can't create outfile %s\n",sfname);
+		psf_sndClose(ifd);
+		return 1;
+	}
+    peaks = (PSF_CHPEAK*)  malloc(sizeof(PSF_CHPEAK) * outchans);
+    memset(peaks,0,sizeof(PSF_CHPEAK) * outchans);
+
+	halfsec = props.srate / 2;
+	framepos = 0;
+	printf("\ndecoding:\n");
+	while((got = psf_sndReadFloatFrames(ifd,abfframe,1))==1){
+        memset(&abfsample,0,sizeof(ABFSAMPLE));
+        copyfunc(&abfsample,abfframe);
+        decodefunc(&abfsample,frame,1);            
+		if(0 > psf_sndWriteFloatFrames(ofd,frame,1)){
+			fprintf(stderr,"error writing to outfile\n");
+			psf_sndClose(ifd);
+			psf_sndClose(ofd);
+			return 1;
+		}
+
+		if((framepos % halfsec) == 0){
+			printf("%.2lf secs\r",(double) framepos / (double) props.srate);
+            fflush(stdout);
+        }
+		framepos++;
+	}
+
+	if(got != 0){
+		fprintf(stderr,"warning: not all data was read\n");
+	}
+	printf("\n%.4lf secs\nWritten %d frames to %s\n",(double)framepos / (double) props.srate,framepos,sfname);
+	
+    if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
+        printf("PEAK values:\n");
+        for(i=0; i < outchans; i++){
+            double val, dbval;
+            val = (double) peaks[i].val;
+            
+            if(val > 0.0){
+                dbval = 20.0 * log10(val);
+                printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+                       val,dbval,(unsigned int)peaks[i].pos,(double)peaks[i].pos / (double) props.srate);
+            }
+            else{
+                printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
+                       val,(unsigned int)peaks[i].pos,(double)peaks[i].pos / (double) props.srate); 
+            }
+        }
+    }
+    printf("\n");
+	psf_sndClose(ifd);
+	psf_sndClose(ofd);
+    if(peaks)
+        free(peaks);
+	psf_finish();
+	return 0;
+}

+ 106 - 0
dev/externals/mctools/fmdcode.h

@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/* fmdcode.h */
+
+/*
+ Channel order is WXYZ,RSTUV,KLMNOPQ
+ 
+ The number of channels defines the order of the soundfield:
+ 2 channel = UHJ 
+ 3 channel = h   = 1st order horizontal
+ 4 channel = f   = 1st order 3-D
+ 5 channel = hh  = 2nd order horizontal
+ 6 channel = fh  = 2nd order horizontal + 1st order height (formerly
+                                                            called 2.5 order)
+ 7 channel = hhh = 3rd order horizontal
+ 8 channel = fhh = 3rd order horizontal + 1st order height
+ 9 channel = ff  = 2nd order 3-D
+ 11 channel = ffh = 3rd order horizontal + 2nd order height
+ 16 channel = fff = 3rd order 3-D
+ 
+ 
+ Horizontal   Height  Soundfield   Number of    Channels
+ order 	      order 	  type      channels 	
+ 1 	         0 	       horizontal 	  3 	    WXY
+ 1 	         1 	      full-sphere 	  4 	    WXYZ
+ 2 	         0 	       horizontal 	  5 	    WXY....UV
+ 2 	         1 	       mixed-order    6 	    WXYZ...UV
+ 2 	         2 	      full-sphere     9 	    WXYZRSTUV
+ 3           0 	       horizontal 	  7 	    WXY....UV.....PQ
+ 3 	         1         mixed-order 	  8 	    WXYZ...UV.....PQ
+ 3 	         2 	       mixed-order 	 11 	    WXYZRSTUV.....PQ
+ 3 	         3 	      full-sphere 	 16 	    WXYZRSTUVKLMNOPQ
+ */
+
+typedef struct abf_samp {
+	float W;
+	float X;
+	float Y;
+	float Z;
+    float R;
+    float S;
+    float T;
+	float U;
+    float V;
+} ABFSAMPLE;
+
+typedef void (*fmhcopyfunc)(ABFSAMPLE*,const float*);
+
+typedef void (*fmhdecodefunc)(const ABFSAMPLE*, float*,unsigned int);
+//void bfdcode4(float *inbuf,long numframes);
+void fmhcopy_3(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_4(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_5(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_6(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_7(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_8(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_9(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_11(ABFSAMPLE* abf,const float*buf);
+void fmhcopy_16(ABFSAMPLE* abf,const float*buf);
+
+
+// i1 = inphase 1st order, etc
+void fm_i1_mono(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_stereo(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_square(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_square(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_quad(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_quad(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_pent(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_pent(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_surr(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_surr(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes);
+void fm_i1_surr6(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_surr6(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes);
+void dm_i1_surr(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes);
+void dm_i1_surr6(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes);
+void dm_i2_surr(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes);
+void dm_i2_surr6(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes);
+void fm_i1_hex(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_hex(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_oct1(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_oct1(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_oct2(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_oct2(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_cube(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_cube(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i1_cubex(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);
+void fm_i2_cubex(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes);

+ 32 - 0
dev/externals/mctools/fmhcube1.txt

@@ -0,0 +1,32 @@
+f left low	<0.5774,0.5774,-0.5774>		0.1768	0.1140	0.1140	-0.1140	0.0000	-0.0369	-0.0369	0.0000	0.0369
+f right	low 	<0.5774,-0.5774,-0.5774>	0.1768	0.1140	-0.1140	-0.1140	0.0000	-0.0369	0.0369	0.0000	-0.0369
+r right low	<-0.5774,-0.5774,-0.5774>	0.1768	-0.1140	-0.1140	-0.1140	0.0000	0.0369	0.0369	0.0000	0.0369
+r left low	<-0.5774,0.5774,-0.5774>	0.1768	-0.1140	0.1140	-0.1140	0.0000	0.0369	-0.0369	0.0000	-0.0369
+f left high	<0.5774,0.5774,0.5774>		0.1768	0.1140	0.1140	0.1140	0.0000	0.0369	0.0369	0.0000	0.0369
+f right high	<0.5774,-0.5774,0.5774>		0.1768	0.1140	-0.1140	0.1140	0.0000	0.0369	-0.0369	0.0000	-0.0369
+r right high	<-0.5774,-0.5774,0.5774>	0.1768	-0.1140	-0.1140	0.1140	0.0000	-0.0369	-0.0369	0.0000	0.0369
+r left high	<-0.5774,0.5774,0.5774>		0.1768	-0.1140	0.1140	0.1140	0.0000	-0.0369	0.0369	0.0000	-0.0369
+
+
+Csound order					W	  X	  Y       Z      R         S      T        U       V
+f left low	<0.5774,0.5774,-0.5774>		0.1768	 0.1140	 0.1140	-0.1140	0.0000	-0.0369	-0.0369	0.0000	 0.0369
+f left high	<0.5774,0.5774,0.5774>		0.1768	 0.1140	 0.1140	 0.1140	0.0000	 0.0369	 0.0369	0.0000	 0.0369
+r left low	<-0.5774,0.5774,-0.5774>	0.1768	-0.1140	 0.1140	-0.1140	0.0000	 0.0369	-0.0369	0.0000	-0.0369
+r left high	<-0.5774,0.5774,0.5774>		0.1768	-0.1140	 0.1140	 0.1140	0.0000	-0.0369	 0.0369	0.0000	-0.0369
+r right low	<-0.5774,-0.5774,-0.5774>	0.1768	-0.1140	-0.1140	-0.1140	0.0000	 0.0369	 0.0369	0.0000	 0.0369
+r right high	<-0.5774,-0.5774,0.5774>	0.1768	-0.1140	-0.1140	 0.1140	0.0000	-0.0369	-0.0369	0.0000	 0.0369
+f right	low 	<0.5774,-0.5774,-0.5774>	0.1768	 0.1140	-0.1140	-0.1140	0.0000	-0.0369	 0.0369	0.0000	-0.0369
+f right high	<0.5774,-0.5774,0.5774>		0.1768	 0.1140	-0.1140	 0.1140	0.0000	 0.0369	-0.0369	0.0000	-0.0369
+
+WAVEX ORDER, LOW + HIGH
+
+f left low	<0.5774,0.5774,-0.5774>		0.1768	 0.1140	 0.1140	-0.1140	0.0000	-0.0369	-0.0369	0.0000	 0.0369
+f right	low 	<0.5774,-0.5774,-0.5774>	0.1768	 0.1140	-0.1140	-0.1140	0.0000	-0.0369	 0.0369	0.0000	-0.0369
+r left low	<-0.5774,0.5774,-0.5774>	0.1768	-0.1140	 0.1140	-0.1140	0.0000	 0.0369	-0.0369	0.0000	-0.0369
+r right low	<-0.5774,-0.5774,-0.5774>	0.1768	-0.1140	-0.1140	-0.1140	0.0000	 0.0369	 0.0369	0.0000	 0.0369
+
+f left high	<0.5774,0.5774,0.5774>		0.1768	 0.1140	 0.1140	 0.1140	0.0000	 0.0369	 0.0369	0.0000	 0.0369
+f right high	<0.5774,-0.5774,0.5774>		0.1768	 0.1140	-0.1140	 0.1140	0.0000	 0.0369	-0.0369	0.0000	-0.0369
+r left high	<-0.5774,0.5774,0.5774>		0.1768	-0.1140	 0.1140	 0.1140	0.0000	-0.0369	 0.0369	0.0000	-0.0369
+r right high	<-0.5774,-0.5774,0.5774>	0.1768	-0.1140	-0.1140	 0.1140	0.0000	-0.0369	-0.0369	0.0000	 0.0369
+

+ 712 - 0
dev/externals/mctools/fmhfuncs.c

@@ -0,0 +1,712 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/* fmhfuncs.c */
+#include "fmdcode.h"
+
+/* TODO: expand to handle numframes frames? */
+
+void fmhcopy_3(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf;
+}
+
+void fmhcopy_4(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->Z = *buf;
+}
+
+void fmhcopy_5(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->U = *buf++;
+    abf->V = *buf;
+}
+
+void fmhcopy_6(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->Z = *buf++;
+    abf->U = *buf++;
+    abf->V = *buf;
+}
+// following discard 3rd order chans
+void fmhcopy_7(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->U = *buf++;
+    abf->V = *buf;
+}
+
+void fmhcopy_8(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->Z = *buf++;
+    abf->U = *buf++;
+    abf->V = *buf;
+}
+// these identical for 2nd order horiz max, but may be expanded later!
+void fmhcopy_9(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->Z = *buf++;
+    abf->R = *buf++;
+    abf->S = *buf++;
+    abf->T = *buf++;
+    abf->U = *buf++;
+    abf->V = *buf;
+}
+
+void fmhcopy_11(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->Z = *buf++;
+    abf->R = *buf++;
+    abf->S = *buf++;
+    abf->T = *buf++;
+    abf->U = *buf++;
+    abf->V = *buf;
+}
+void fmhcopy_16(ABFSAMPLE* abf,const float*buf)
+{
+    abf->W = *buf++;
+    abf->X = *buf++;
+    abf->Y = *buf++;
+    abf->Z = *buf++;
+    abf->R = *buf++;
+    abf->S = *buf++;
+    abf->T = *buf++;
+    abf->U = *buf++;
+    abf->V = *buf;
+}
+
+/********** DECODE FUNCS *************/
+/* TODO: complete support for numframes > 1 */
+
+void fm_i1_mono(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+    int i;	
+	float *p_out = outbuf;
+	double aw;
+    for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.7071;
+		*p_out++ = (float) aw;  		  
+	}
+}
+
+void fm_i1_stereo(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+    int i;	
+	float *p_out = outbuf;
+	double aw,ay;
+    for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.7071;
+		ay = (double) inbuf->Y * 0.5;		
+		
+		*p_out++ = (float) (aw +  ay);  
+		*p_out++ = (float) (aw  - ay);  
+	}
+}
+
+void fm_i1_square(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.35355;
+		ax = (double) inbuf->X * 0.17677;
+		ay = (double) inbuf->Y * 0.17677;		
+		
+		*p_out++ = (float) (aw + ax + ay);  //FL
+		*p_out++ = (float) (aw - ax + ay);  //RL
+		*p_out++ = (float) (aw - ax - ay);  //RR
+		*p_out++ = (float) (aw + ax - ay);  //FR
+	}
+}
+void fm_i2_square(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;		
+	float *p_out = outbuf;	
+	double aw,ax,ay,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.3536;
+		ax = (double) inbuf->X * 0.2434;
+		ay = (double) inbuf->Y * 0.2434;		
+		av = (double) inbuf->V * 0.0964;
+		*p_out++ = (float) (aw + ax + ay + av);  //FL
+		*p_out++ = (float) (aw - ax + ay - av ); //RL
+		*p_out++ = (float) (aw - ax - ay + av);  //RR
+		*p_out++ = (float) (aw + ax - ay - av);  //FR
+	}
+}
+/* ditto, RLRL layout for WAVEX */
+void fm_i1_quad(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.35355;
+		ax = (double) inbuf->X * 0.17677;
+		ay = (double) inbuf->Y * 0.17677;		
+		
+		*p_out++ = (float) (aw + ax + ay);  //FL
+        *p_out++ = (float) (aw + ax - ay);  //FR
+		*p_out++ = (float) (aw - ax + ay);  //RL
+		*p_out++ = (float) (aw - ax - ay);  //RR
+		
+	}
+}
+void fm_i2_quad(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;		
+	float *p_out = outbuf;	
+	double aw,ax,ay,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.3536;
+		ax = (double) inbuf->X * 0.2434;
+		ay = (double) inbuf->Y * 0.2434;		
+		av = (double) inbuf->V * 0.0964;
+		*p_out++ = (float) (aw + ax + ay + av);  //FL
+        *p_out++ = (float) (aw + ax - ay - av);  //FR
+		*p_out++ = (float) (aw - ax + ay - av ); //RL
+		*p_out++ = (float) (aw - ax - ay + av);  //RR
+		
+	}
+}
+
+
+//front pair angle 72deg
+void fm_i1_pent(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.2828;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		
+		*p_out++ = (float) (aw + (ax*0.1618) + (ay*0.1176));  //FL
+		*p_out++ = (float) (aw - (ax*0.0618) + (ay*0.1902));  
+		*p_out++ = (float) (aw - (ax*0.2));  
+		*p_out++ = (float) (aw - (ax*0.0618) - (ay*0.1902));  
+        *p_out++ = (float) (aw + (ax*0.1618) - (ay*0.1176)); //FR
+	}
+}
+
+void fm_i2_pent(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;	
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.2828;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;	
+        au = (double) inbuf->U;
+        av = (double) inbuf->V;
+		
+		*p_out++ = (float) (aw + (ax*0.2227) + (ay*0.1618) + (au*0.0238) + (av * 0.0733));  
+		*p_out++ = (float) (aw - (ax*0.0851) + (ay*0.2619) - (au*0.0624) - (av * 0.0453));  
+		*p_out++ = (float) (aw - (ax*0.2753)               + (au * 0.0771)              );  
+		*p_out++ = (float) (aw - (ax*0.0851) - (ay*0.2619) - (au*0.0624) + (av * 0.0453));  
+        *p_out++ = (float) (aw + (ax*0.2227) - (ay*0.1618) + (au*0.0238) - (av * 0.0733));
+	}
+}
+
+/* FMH only defines 1st order decode */ 
+void fm_i1_surr(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		/* TODO: fix this order! */
+		*p_out++ = (float) ((aw * 0.169)  + (ax*0.0797) + (ay * 0.0891));   //L
+		*p_out++ = (float) ((aw * 0.1635) + (ax*0.0923));                   //C    ///???
+		*p_out++ = (float) ((aw * 0.169)  - (ax*0.0797) - (ay * 0.0891));   //R    ///????
+		*p_out++ = (float) ((aw * 0.4563) - (ax*0.1259) + (ay * 0.1543));   //LS
+        *p_out++ = (float) ((aw * 0.4563) - (ax*0.1259) - (ay * 0.1543));   //RS
+	}
+}
+/* from Bruce Wiggins via Csound */
+void fm_i2_surr(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		au = (double) inbuf->U;
+        av = (double) inbuf->V;
+        
+		*p_out++ = (float) ((aw * 0.405) + (ax*0.32) + (ay * 0.31)  + (au * 0.085) + (av * 0.125));   //L
+        *p_out++ = (float) ((aw * 0.405) + (ax*0.32) - (ay * 0.31)  + (au * 0.085) - (av * 0.125));   //R
+		*p_out++ = (float) ((aw * 0.085) + (ax*0.04)                + (au * 0.045)               );   //C
+		*p_out++ = (float) ((aw * 0.635) - (ax*0.335) + (ay * 0.28) - (au * 0.08)  + (av * 0.08));    //LS
+        *p_out++ = (float) ((aw * 0.635) - (ax*0.335) - (ay * 0.28) - (au * 0.08)  - (av * 0.08));    //RS
+	}
+}
+
+/* 5.1 versions - silent LFE */
+/* FMH only defines 1st order decode */ 
+void fm_i1_surr6(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		
+		*p_out++ = (float) ((aw * 0.169)  + (ax*0.0797) + (ay * 0.0891));   //L
+		*p_out++ = (float) ((aw * 0.1635) + (ax*0.0923));                   //C
+		*p_out++ = (float) ((aw * 0.169)  - (ax*0.0797) - (ay * 0.0891));   //R
+        *p_out++ = 0.0f;                                                    //LFE
+		*p_out++ = (float) ((aw * 0.4563) - (ax*0.1259) + (ay * 0.1543));   //LS
+        *p_out++ = (float) ((aw * 0.4563) - (ax*0.1259) - (ay * 0.1543));   //RS
+	}
+}
+/* from Bruce Wiggins via Csound */
+void fm_i2_surr6(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		au = (double) inbuf->U;
+        av = (double) inbuf->V;
+        
+		*p_out++ = (float) ((aw * 0.405) + (ax*0.32) + (ay * 0.31)  + (au * 0.085) + (av * 0.125));   //L
+        *p_out++ = (float) ((aw * 0.405) + (ax*0.32) - (ay * 0.31)  + (au * 0.085) - (av * 0.125));   //R
+		*p_out++ = (float) ((aw * 0.085) + (ax*0.04)                + (au * 0.045)               );   //C
+        *p_out++ = 0.0f;                                                                              //LFE
+		*p_out++ = (float) ((aw * 0.635) - (ax*0.335) + (ay * 0.28) - (au * 0.08)  + (av * 0.08));    //LS
+        *p_out++ = (float) ((aw * 0.635) - (ax*0.335) - (ay * 0.28) - (au * 0.08)  - (av * 0.08));    //RS
+	}
+}
+
+// 1st order 5.0
+void dm_i1_surr(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		
+        
+		*p_out++ = (float) ((aw * 0.4597)  + (ax*0.4536) + (ay * 0.3591));   //L
+        *p_out++ = (float)  ((aw * 0.4597)  + (ax*0.4536) - (ay * 0.3591));  //R 
+		*p_out++ = 0.0f;                                                     //C
+		
+		*p_out++ = (float) ((aw * 0.5662) - (ax*0.3681) + (ay * 0.4606));    //LS
+        *p_out++ = (float) ((aw * 0.5662) - (ax*0.3681) - (ay * 0.4606));    //RS
+    }
+}
+//1st order 5.1
+void dm_i1_surr6(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		
+        
+		*p_out++ = (float) ((aw * 0.4597)  + (ax*0.4536) + (ay * 0.3591));   //L
+        *p_out++ = (float)  ((aw * 0.4597)  + (ax*0.4536) - (ay * 0.3591));  //R 
+		*p_out++ = 0.0f;                                                     //C
+		*p_out++ = 0.0f;                                                     //LFE
+		*p_out++ = (float) ((aw * 0.5662) - (ax*0.3681) + (ay * 0.4606));    //LS
+        *p_out++ = (float) ((aw * 0.5662) - (ax*0.3681) - (ay * 0.4606));    //RS
+    }
+}
+// 2nd order 5.0
+void dm_i2_surr(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		au = (double) inbuf->U;
+        av = (double) inbuf->V;
+        
+		*p_out++ = (float) ((aw * 0.3314)  + (ax*0.4097) + (ay * 0.3487) + (au * 0.0828) + (av*0.1489));  //L
+        *p_out++ = (float) ((aw * 0.3314)  + (ax*0.4097) - (ay * 0.3487) + (au * 0.0828) - (av*0.1489));  //R 
+		*p_out++ = (float) ((aw * 0.0804)  + (ax * 0.1327));                                              //C
+		*p_out++ = (float) ((aw * 0.6025) - (ax*0.3627) + (ay * 0.4089) - (au * 0.0567));                 //LS
+        *p_out++ = (float) ((aw * 0.6025) - (ax*0.3627) - (ay * 0.4089) - (au * 0.0567));                 //RS
+    }
+}
+// 2nd order 5.1
+void dm_i2_surr6(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		au = (double) inbuf->U;
+        av = (double) inbuf->V;
+        
+		*p_out++ = (float) ((aw * 0.3314)  + (ax*0.4097) + (ay * 0.3487) + (au * 0.0828) + (av*0.1489));  //L
+        *p_out++ = (float) ((aw * 0.3314)  + (ax*0.4097) - (ay * 0.3487) + (au * 0.0828) - (av*0.1489));  //R 
+		*p_out++ = (float) ((aw * 0.0804)  + (ax * 0.1327));                                              //C
+		*p_out++ = 0.0f;                                                                                  //LFE
+		*p_out++ = (float) ((aw * 0.6025) - (ax*0.3627) + (ay * 0.4089) - (au * 0.0567));                 //LS
+        *p_out++ = (float) ((aw * 0.6025) - (ax*0.3627) - (ay * 0.4089) - (au * 0.0567));                 //RS
+    }
+}
+
+
+void fm_i1_hex(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.2357;
+		ax = (double) inbuf->X * 0.1443;
+		ay = (double) inbuf->Y;		
+		
+		*p_out++ = (float) (aw + ax + (ay * 0.0833));  //FL
+		*p_out++ = (float) (aw      + (ay * 0.1667));  //SL
+		*p_out++ = (float) (aw - ax + (ay * 0.0833));  //RL
+		*p_out++ = (float) (aw - ax - (ay * 0.0833));  //RR
+        *p_out++ = (float) (aw      - (ay * 0.1667));  //SR
+        *p_out++ = (float) (aw + ax - (ay * 0.0833));  //FR
+	}
+}
+void fm_i2_hex(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;	
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.2357;
+		ax = (double) inbuf->X * 0.1987;
+		ay = (double) inbuf->Y;
+		au = (double) inbuf->U;
+        av = (double) inbuf->V * 0.0556;
+		
+		*p_out++ = (float) (aw + ax + (ay * 0.1147) + (au * 0.0321) + av);  //FL
+		*p_out++ = (float) (aw      + (ay * 0.2294) - (au * 0.0643)     );  //SL
+		*p_out++ = (float) (aw - ax + (ay * 0.1147) + (au * 0.0321) - av);  //RL
+		*p_out++ = (float) (aw - ax - (ay * 0.1147) + (au * 0.0321) + av);  //RR
+        *p_out++ = (float) (aw      - (ay * 0.2294) - (au * 0.0643)     );  //SR
+        *p_out++ = (float) (aw + ax - (ay * 0.1147) + (au * 0.0321) - av);  //FR
+	}
+}
+
+void fm_i1_oct1(const ABFSAMPLE *inbuf,float*outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.1768;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		
+		*p_out++ = (float) (aw + (ax * 0.1155) + (ay * 0.0478));  
+		*p_out++ = (float) (aw + (ax * 0.0478) + (ay * 0.1155));  
+		*p_out++ = (float) (aw - (ax * 0.0478) + (ay * 0.1155));  
+		*p_out++ = (float) (aw - (ax * 0.1155) + (ay * 0.0478));  
+        *p_out++ = (float) (aw - (ax * 0.231)  - (ay * 0.0957));  
+        *p_out++ = (float) (aw - (ax * 0.0478) - (ay * 0.1155));  
+        *p_out++ = (float) (aw + (ax * 0.0478) - (ay * 0.1155));  
+        *p_out++   = (float) (aw + (ax * 0.1155) - (ay * 0.0478));  
+	}
+}
+void fm_i2_oct1(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;	
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.17677;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;
+		au = (double) inbuf->U * 0.03417;
+		av = (double) inbuf->V * 0.03417;
+        
+		*p_out++ = (float) (aw + (ax * 0.15906) + (ay * 0.06588) + au + av);  
+		*p_out++ = (float) (aw + (ax * 0.06588) + (ay * 0.15906) - au + av);  
+		*p_out++ = (float) (aw - (ax * 0.06588) + (ay * 0.15906) - au - av);  
+		*p_out++ = (float) (aw - (ax * 0.15906) + (ay * 0.06588) + au - av);  
+        *p_out++ = (float) (aw - (ax * 0.15906) - (ay * 0.06588) + au + av);  
+        *p_out++ = (float) (aw - (ax * 0.06588) - (ay * 0.15906) - au + av);  
+        *p_out++ = (float) (aw + (ax * 0.06588) - (ay * 0.15906) - au - av);  
+        *p_out++ = (float) (aw + (ax * 0.15906) - (ay * 0.06588) + au - av);  
+	}
+}
+
+void fm_i1_oct2(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.1768;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;		
+		
+		*p_out++ = (float) (aw + (ax * 0.125)                 );  
+		*p_out++ = (float) (aw + (ax * 0.0884) + (ay * 0.0884));  
+		*p_out++ = (float) (aw                 + (ay * 0.125) );  
+		*p_out++ = (float) (aw - (ax * 0.0884) + (ay * 0.0884));  
+        *p_out++ = (float) (aw - (ax * 0.125)                 );  
+        *p_out++ = (float) (aw - (ax * 0.0884) - (ay * 0.0884));  
+        *p_out++ = (float) (aw                 - (ay * 0.125) );  
+        *p_out++ = (float) (aw + (ax * 0.0884) - (ay * 0.0884));  
+	}
+}
+void fm_i2_oct2(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;	
+	double aw,ax,ay,au,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.1768;
+		ax = (double) inbuf->X;
+		ay = (double) inbuf->Y;
+		au = (double) inbuf->U * 0.0482;
+		av = (double) inbuf->V * 0.0482;
+        
+		*p_out++ = (float) (aw + (ax * 0.1721)                 + au     );  
+		*p_out++ = (float) (aw + (ax * 0.1217) + (ay * 0.1217)      + av);  
+		*p_out++ = (float) (aw                 + (ay * 0.1721) - au     );  
+		*p_out++ = (float) (aw - (ax * 0.1217) + (ay * 0.1217)      - av);  
+        *p_out++ = (float) (aw - (ax * 0.1721)                 + au     );  
+        *p_out++ = (float) (aw - (ax * 0.1217) - (ay * 0.1217)      + av);  
+        *p_out++ = (float) (aw                 - (ay * 0.1721) - au     );  
+        *p_out++ = (float) (aw + (ax * 0.1217) - (ay * 0.1217)      - av);  
+	}
+}
+
+/* csound order; low/high anti-clockwise. 
+FMH page order, 4 low folowed by 4 high , clockwise! */
+void fm_i1_cube(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay,az;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.17677;
+		ax = (double) inbuf->X * 0.07216;
+		ay = (double) inbuf->Y * 0.07216;
+		az = (double) inbuf->Z * 0.07216;
+		
+		*p_out++ = (float) (aw + ax + ay - az);  // FL low
+		*p_out++ = (float) (aw + ax + ay + az);  // FL hi
+        
+		*p_out++ = (float) (aw - ax + ay - az);  // RL low
+		*p_out++ = (float) (aw - ax + ay + az);  //    hi
+        
+        *p_out++ = (float) (aw - ax - ay - az);  // RR low
+        *p_out++ = (float) (aw - ax - ay + az);  //   hi
+        
+        *p_out++ = (float) (aw + ax - ay - az);  // FR low
+        *p_out++ = (float) (aw + ax - ay + az);  //    hi
+	}
+}
+void fm_i2_cube(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;	
+	double aw,ax,ay,az,as,at,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.1768;
+		ax = (double) inbuf->X * 0.114;
+		ay = (double) inbuf->Y * 0.114;
+        az = (double) inbuf->Z * 0.114;
+        as = (double) inbuf->S * 0.0369;
+        at = (double) inbuf->T * 0.0369;
+		av = (double) inbuf->V * 0.0369;
+        
+		*p_out++ = (float) (aw + ax + ay - az - as - at + av); //FL low 
+		*p_out++ = (float) (aw + ax + ay + az + as + at + av); //   hi 
+		
+        *p_out++ = (float) (aw - ax + ay - az + as - at - av); //RL low
+		*p_out++ = (float) (aw - ax + ay + az - as + at - av);  
+        
+        *p_out++ = (float) (aw - ax - ay - az + as + at + av); // RR low
+        *p_out++ = (float) (aw - ax - ay + az - as - at + av);  
+        
+        *p_out++ = (float) (aw + ax - ay - az - as + at - av);  // FR low
+        *p_out++ = (float) (aw + ax - ay + az + as - at - av);   
+	}
+}
+/* ditto, wavex order */
+/* Front L, front R, Back L, Back R; top Front L, Top Fr R, Top Back L, Top back R */
+void fm_i1_cubex(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;
+	double aw,ax,ay,az;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.17677;
+		ax = (double) inbuf->X * 0.07216;
+		ay = (double) inbuf->Y * 0.07216;
+		az = (double) inbuf->Z * 0.07216;
+		
+		*p_out++ = (float) (aw + ax + ay - az);  // FL low
+        *p_out++ = (float) (aw + ax - ay - az);  // FR low
+        *p_out++ = (float) (aw - ax + ay - az);  // RL low
+        *p_out++ = (float) (aw - ax - ay - az);  // RR low
+        
+		*p_out++ = (float) (aw + ax + ay + az);  // FL hi
+        *p_out++ = (float) (aw + ax - ay + az);  // FR hi
+		*p_out++ = (float) (aw - ax + ay + az);  // RL hi
+        *p_out++ = (float) (aw - ax - ay + az);  // RR hi
+	}
+}
+void fm_i2_cubex(const ABFSAMPLE *inbuf,float *outbuf,unsigned int numframes)
+{
+	int i;	
+	float *p_out = outbuf;	
+	double aw,ax,ay,az,as,at,av;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double) inbuf->W * 0.1768;
+		ax = (double) inbuf->X * 0.114;
+		ay = (double) inbuf->Y * 0.114;
+        az = (double) inbuf->Z * 0.114;
+        as = (double) inbuf->S * 0.0369;
+        at = (double) inbuf->T * 0.0369;
+		av = (double) inbuf->V * 0.0369;
+        
+		*p_out++ = (float) (aw + ax + ay - az - as - at + av);  // FL low
+        *p_out++ = (float) (aw + ax - ay - az - as + at - av);  // FR low
+        *p_out++ = (float) (aw - ax + ay - az + as - at - av);  // RL low
+        *p_out++ = (float) (aw - ax - ay - az + as + at + av);  // RR low
+		
+        *p_out++ = (float) (aw + ax + ay + az + as + at + av);  // FL  hi 
+		*p_out++ = (float) (aw + ax - ay + az + as - at - av);  // FR  hi
+		*p_out++ = (float) (aw - ax + ay + az - as + at - av);  // RL  hi 
+        *p_out++ = (float) (aw - ax - ay + az - as - at + av);  // RR  hi 
+	}
+}
+
+
+#ifdef NOTDEF
+void bfdcode4(float *inbuf,long numframes)
+{
+	int i;	
+	float *p_buf = inbuf;	
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		aw = (double)(p_buf[0]) ;
+		ax = (double)(p_buf[1]) * 0.707;
+		ay = (double)(p_buf[2]) * 0.707;		
+		//decode frame
+		*p_buf++ = (float)(0.3333 * (aw + ax + ay)); //FL
+		*p_buf++ = (float)(0.3333 * (aw + ax - ay)); //FR
+		*p_buf++ = (float)(0.3333 * (aw - ax + ay)); //RL
+		*p_buf++ = (float)(0.3333 * (aw - ax - ay));  //RR
+	}
+}
+
+
+/* handle 3ch in to 4ch out! */
+
+void bfdcode324(float *inbuf,float*outbuf,long numframes)
+{
+	int i;	
+	float *p_buf = inbuf;
+	float * p_outbuf = outbuf;
+	double aw,ax,ay;
+	
+	for(i=0;i < numframes; i++){
+		int j;
+		aw = (double)(*p_buf++) ;
+		ax = (double)(*p_buf++) * 0.707;
+		ay = (double)(*p_buf++) * 0.707;
+        
+		//decode frame
+		*p_outbuf++ = (float)(0.3333 * (aw + ax + ay));
+		*p_outbuf++ = (float)(0.3333 * (aw + ax - ay));
+		*p_outbuf++ = (float)(0.3333 * (aw - ax + ay));
+		*p_outbuf++ = (float)(0.3333 * (aw - ax - ay));
+	}
+}
+#endif

+ 504 - 0
dev/externals/mctools/interlx.c

@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/*TODO: fix bug writing header when using -x with .amb extension (omits cbSize setting) */
+
+/*interlx.c */
+/* v1.3. nov 2005; support placeholder arg for silent channel */
+/* v 1.7 beta ; added surr 5.0; updated sfsys with bit-correct 24bit copy */
+/* v 1.8 March 2009 updated sfsys  for AIFC int24 suport */
+
+/* OCT 2009 portsf(64) version. int24 aifc supported for reading. */
+/* v2.0.1 Jan 2010: Corrected usage message to refer to outfile.  */
+/* Nov 2013 added MC_SURR_6_1 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <memory.h>
+#include <string.h>
+#include <ctype.h>
+#include "portsf.h"
+
+/*
+The number of channels defines the order of the soundfield:
+ 3 channel = h   = 1st order horizontal
+ 4 channel = f   = 1st order 3-D
+ 5 channel = hh  = 2nd order horizontal
+ 6 channel = fh  = 2nd order horizontal + 1st order height (formerly called 2.5 order)
+ 7 channel = hhh = 3rd order horizontal
+ 8 channel = fhh = 3rd order horizontal + 1st order height
+ 9 channel = ff  = 2nd order 3-D
+11 channel = ffh = 3rd order horizontal + 2nd order height
+16 channel = fff = 3rd order 3-D
+*/
+
+#define N_BFORMATS (10)
+static const int bformats[N_BFORMATS] = {2,3,4,5,6,7,8,9,11,16};
+#define MAX_INFILES (16)	//should keep most people happy! Won't get much more on a cmdline anyway
+
+enum {OPT_STD_WAVE,OPT_WAVEX_GENERIC,OPT_WAVEX,OPT_WAVEX_LCRS,OPT_WAVEX_SURROUND,OPT_WAVEX_BFORMAT,
+   OPT_SURR_5_0,OPT_WAVEX_7_1,OPT_WAVEX_CUBE,OPT_WAVEX_6_1, OPT_MAXOPTS};
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+#ifndef max
+#define max(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+void
+usage()
+{
+	fprintf(stderr,"\nCDP MCTOOLS: INTERLX v2.1.0 (c) RWD,CDP 2009,2013\n"
+			"Interleave mono or stereo files into a multi-channel file\n"
+			"Usage: interlx [-tN] outfile infile1 infile2 [infile3...]\n"
+			
+			"       Up to %d files may be interleaved.\n"						
+			"       Output format is taken from infile1.\n"
+			"       Files must match sample rate and number of channels,\n"
+			"          but can have different sample types.\n"
+			"       To create a silent channel, for infile2 onwards,\n"
+			"          use 0 (zero) as filename. Infile1 must be a soundfile.\n"
+			"       NB: Speaker-positions in WAVE_EX infiles are ignored\n"
+			"       Note that the same infile can be listed multiple times,\n"
+			"          for example, to write a mono file as stereo, quad, etc.\n"
+			"       The .amb B-Format extension is supported: \n"
+			"          the program warns if channel count is anomalous.\n"
+			"       recognised Bformat channel counts: 3,4,5,6,7,8,9,11,16.\n"
+            "   -tN  : write outfile format as type N\n"
+	        "    Available formats:\n"
+			"    0   : (default) standard soundfile (.wav, .aif, .afc, .aifc)\n"
+			"    1   : generic WAVE_EX (no speaker assignments)\n"
+			"    2   : WAVE_EX mono/stereo/quad(LF,RF,LR,RR)   - total chans must match.\n"
+			"    3   : WAVE_EX quad surround (L,C,R,S)         - total chans must be 4.\n"
+			"    4   : WAVE_EX 5.1 format surround             - total chans must be 6.\n"
+			"    5   : WAVE_EX Ambisonic B-format (W,X,Y,Z...) - extension .amb recommended.\n"
+            "    6   : WAVE_EX 5.0 surround                    - total chans must be 5.\n"
+            "    7   : WAVE_EX 7.1 Surround                    - total chans must be 8.\n"
+            "    8   : WAVE_EX Cube Surround                   - total chans must be 8.\n"
+            "    9   : WAVE_EX 6.1 surround (new in v 2.1.0)   - total chans must be 7.\n"
+			"          in all cases: outfile has sample format of infile1\n"
+			"          NB: types 1 to %d are for WAV format only\n"			
+			,MAX_INFILES,OPT_MAXOPTS-1);
+	
+}
+	
+
+void cleanup(int *sflist)
+{
+
+	int i;
+	for(i=0;i < MAX_INFILES; i++)
+		if(sflist[i] >= 0)
+			psf_sndClose(sflist[i]);
+	psf_finish();
+}
+
+int main(int argc, char *argv[])
+{
+
+	long outframesize,thissize;
+	int i,ofd;
+	int ifdlist[MAX_INFILES];
+	//int force_stype = -1,out_stype;
+    int force_wave = 0;
+	int infilearg,inchans;
+	int num_infiles = 0;
+	int halfsec;
+    MYLONG peaktime;
+	float *outframe	= NULL,*inframe = NULL;
+	PSF_PROPS firstinprops,inprops;
+	PSF_CHPEAK *fpeaks = NULL;
+    int wave_type = -1;
+    char *create_msg = NULL;
+    psf_format informat = PSF_STDWAVE;
+	char* p_dot = NULL;		/* to find extension of outfile */
+	
+	for(i=0;i < MAX_INFILES;i++)
+		ifdlist[i] = -1;
+
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("2.0.1.\n");
+        return 0;
+    }
+    
+	if(argc < 4) {
+		fprintf(stderr,"interlx: insufficient arguments\n");
+		usage();
+		exit(1);
+	}
+
+	while(argv[1][0] =='-'){
+		
+		switch(argv[1][1]){
+        case('t'):
+			if(argv[1][2]=='\0'){
+				fprintf(stderr,"-t flag requires parameter\n");
+				usage();
+				exit(1);
+			}
+			wave_type = atoi(&(argv[1][2]));
+			if((wave_type < 0) || wave_type >= OPT_MAXOPTS){
+				fprintf(stderr,"wave type out of range\n");
+				usage();
+				exit(1);
+			}
+			force_wave = 1;
+			break;
+		default:
+			fprintf(stderr,"\nabfpan: error: illegal flag option %s",argv[1]);
+			exit(1);
+		}
+
+		argc--; argv++;
+	}
+
+	if(argc < 4){
+		fprintf(stderr,"interlx error: at least two infiles required!\n");
+		usage();
+		exit(1);
+	}
+
+	if(psf_init()){
+		printf("Startup failure.\n");
+		return  1;
+	}
+	
+	//open first infile and get properties
+	ifdlist[0] = psf_sndOpen(argv[2],&firstinprops,0);
+	if(ifdlist[0] < 0){
+		fprintf(stderr,"unable to open infile %s\n",argv[2]);
+		cleanup(ifdlist);
+		return 1;
+	}
+
+/* we don't know how to deal with speaker positions yet, so disregard these
+	if(firstinprops.chformat > MC_STD){
+		printf(stderr,"Warning,interlx: ignoring source file speaker positions\n");
+	}
+*/
+	outframesize = psf_sndSize(ifdlist[0]);
+	if(outframesize < 0){
+		fprintf(stderr,"unable to read size of infile %s\n",argv[2]);
+		cleanup(ifdlist);
+		return 1;
+	}
+	inchans = firstinprops.chans;
+	/*we can always allow more channels if someone really needs it! */
+	if(!(inchans==1 || inchans==2)){
+		fprintf(stderr,"interlx: error: infile %s has %d channels\n"
+				"\t(only mono and stereo files can be used)\n",argv[2],inchans);
+		cleanup(ifdlist);
+		return 1;
+	}
+	
+	num_infiles = 1;
+	printf("interleaving %d-channel files,sample rate = %d\n",inchans,firstinprops.srate);
+
+	infilearg = 3;
+	while(argv[infilearg] != NULL){
+		if(strcmp(argv[infilearg],"0")==0){
+			ifdlist[num_infiles] = -1;           // mark silent channel
+		}
+		else{
+
+			if((ifdlist[num_infiles] = psf_sndOpen(argv[infilearg],&inprops,0)) < 0){
+				fprintf(stderr,"cannot open infile %s\n",argv[infilearg]);
+				cleanup(ifdlist);
+				return 1;
+			}
+			if(inprops.chans != firstinprops.chans){
+				fprintf(stderr,"interlx: error: channel mismatch from infile %s\n",argv[infilearg]);
+				cleanup(ifdlist);
+				return 1;
+			}
+
+			if(inprops.srate != firstinprops.srate){
+			   fprintf(stderr,"interlx: error: sample rate mismatch from infile %s\n",argv[infilearg]);
+				cleanup(ifdlist);
+				return 1;
+			}
+
+			thissize = psf_sndSize(ifdlist[num_infiles]);
+			if(thissize < 0){
+				fprintf(stderr,"unable to read size of infile %s\n",argv[infilearg]);
+				cleanup(ifdlist);
+				return 1;
+			}			
+			outframesize = max(outframesize,thissize);
+		}
+		
+		infilearg++;
+		num_infiles++;
+		if(num_infiles > MAX_INFILES){
+			fprintf(stderr,"Sorry! too many infiles. Maximum accepted is %d.\n",MAX_INFILES);
+			cleanup(ifdlist);
+			exit(1);
+		}
+
+	}
+
+	
+	inframe = malloc(inchans * sizeof(float));
+	if(inframe==NULL){
+		puts("interlx: error: no memory for input buffer!\n");
+		cleanup(ifdlist);
+		return 1;
+	}
+
+	firstinprops.chans *= num_infiles;
+	outframe = (float *) malloc(firstinprops.chans * sizeof(float));
+	if(outframe==NULL){
+		puts("\ninterlx: error: no memory for output buffer!\n");
+		cleanup(ifdlist);
+		return 1;
+	}
+
+	fpeaks = (PSF_CHPEAK *) calloc(firstinprops.chans,sizeof(PSF_CHPEAK));
+	if(fpeaks==NULL){
+		puts("interlx: error: no memory for internal PEAK buffer\n");
+		cleanup(ifdlist);
+		return 1;
+	}
+    if(force_wave){
+		int i,matched;
+		
+		switch(wave_type){
+        case(OPT_WAVEX_GENERIC):
+			inprops.chformat = MC_STD;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating STD WAVE_EX file";
+			break;
+		case(OPT_WAVEX):
+			switch(firstinprops.chans){
+			case(1):
+				firstinprops.chformat = MC_MONO;
+				informat = PSF_WAVE_EX;
+				create_msg = "creating MONO WAVE_EX file";
+				break;
+			case(2):
+				firstinprops.chformat = MC_STEREO;
+				informat = PSF_WAVE_EX;
+				create_msg = "creating STEREO WAVE_EX file";
+				break;
+			case(4):
+				firstinprops.chformat = MC_QUAD;
+				informat = PSF_WAVE_EX;
+				create_msg = "creating QUAD WAVE_EX file";
+				break;
+			default:
+				fprintf(stderr,"infile nchans incompatible with requested WAVE-EX format\n");
+				usage();
+				cleanup(ifdlist);
+				return 1;				
+			}
+			break;
+		case(OPT_WAVEX_LCRS):
+			if(firstinprops.chans != 4){
+				fprintf(stderr,"result must have four channels\n");
+				usage();
+				cleanup(ifdlist);
+				return 1;
+			}
+			firstinprops.chformat = MC_LCRS;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating LCRS-surround WAVE_EX file";
+			break;
+		case(OPT_WAVEX_SURROUND):
+			if(firstinprops.chans != 6){
+				fprintf(stderr,"result must have six channels\n");
+				usage();
+				cleanup(ifdlist);
+				exit(1);
+			}
+			firstinprops.chformat = MC_DOLBY_5_1;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating 5.1 surround WAVE_EX file";
+			break;
+            
+        case(OPT_SURR_5_0):
+			if(firstinprops.chans != 5){
+				fprintf(stderr,"result must have five channels.\n");
+				usage();
+				cleanup(ifdlist);
+				return 1;
+			}
+			firstinprops.chformat = MC_SURR_5_0;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating 5.0 surround WAVE_EX file";
+			break;
+
+		case(OPT_WAVEX_BFORMAT):
+			matched = 0;
+			for(i=0;i < N_BFORMATS;i++)	{
+				if(firstinprops.chans == bformats[i]){
+					matched = 1;
+					break;
+				}
+			}
+			if(!matched){
+				printf("WARNING: No Bformat definition for %d-channel file.\n",inprops.chans);
+			}
+			firstinprops.chformat = MC_BFMT;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating AMBISONIC B-FORMAT WAVE_EX file";
+			break;
+        case OPT_WAVEX_7_1:
+            if(firstinprops.chans != 8){
+				fprintf(stderr,"result must have  channels\n");
+				usage();
+				cleanup(ifdlist);
+				return 1;
+			}
+			firstinprops.chformat = MC_SURR_7_1;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating 7.1 surround WAVE_EX file";
+			break;
+        case OPT_WAVEX_CUBE:
+            if(firstinprops.chans != 8){
+				fprintf(stderr,"result must have  channels\n");
+				usage();
+				cleanup(ifdlist);
+				return 1;
+			}
+			firstinprops.chformat = MC_CUBE;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating cube surround WAVE_EX file";
+			break;
+		case OPT_WAVEX_6_1:
+            if(firstinprops.chans != 7){
+				fprintf(stderr,"result must have  channels\n");
+				usage();
+				cleanup(ifdlist);
+				return 1;
+			}
+			firstinprops.chformat = MC_SURR_6_1;
+			informat = PSF_WAVE_EX;
+			create_msg = "creating 6.1 surround WAVE_EX file";
+			break;
+		default:
+            inprops.chformat = STDWAVE;
+			informat = PSF_STDWAVE;
+			create_msg = "creating plain sound file";
+			break;
+		}		
+	}
+	
+	/*  want to avoid WAVE_EX if just plain WAVE possible */
+	firstinprops.format = informat;
+		/*firstinprops.chformat = MC_STD;*/		/* RWD April 2006 do this here? */
+	
+	p_dot = strrchr(argv[1],'.');
+	if(stricmp(++p_dot,"amb")==0) {
+		int i;
+		int matched = 0;
+		firstinprops.chformat = MC_BFMT;
+		for(i=0;i < N_BFORMATS;i++)	{
+			if(firstinprops.chans == bformats[i]){
+				matched = 1;
+				break;
+			}
+		}
+		if(!matched)
+			printf("\nWARNING: channel count %d unknown for BFormat.\n",firstinprops.chans);
+
+	}
+    if(!is_legalsize(outframesize,&firstinprops)){
+        fprintf(stderr,"error: outfile size %ld exceeds capacity of format.\n",outframesize);
+        return 1;
+    }
+    printf("\n%s: %d channels, %ld frames.\n",create_msg,firstinprops.chans,outframesize);
+	ofd = psf_sndCreate(argv[1],&firstinprops,0,0,PSF_CREATE_RDWR);
+	
+	
+	if(ofd < 0){
+		fprintf(stderr,"interlx: error: unable to create outfile %s.\n",argv[1]);
+		cleanup(ifdlist);
+		return 1;
+	}
+
+	halfsec = firstinprops.srate / 2;
+	for(i=0;i < outframesize; i++){		// frame loop
+		float *p_framesamp,*p_filesamp;
+		int j;
+		
+		p_framesamp = outframe;
+		memset((char *)outframe,0,firstinprops.chans * sizeof(float));
+
+		for(j=0;j < num_infiles;j++) {	//file loop
+			int k,got;
+            
+			memset((char *)inframe,0,inchans * sizeof(float));
+			if(ifdlist[j] < 0){
+				got = inchans; // placeholder - write silent channel
+			}
+			else{
+				if((got = psf_sndReadFloatFrames(ifdlist[j],inframe,1)) < 0){
+					fprintf(stderr,"interlx: error reading from infile %s\n",argv[2+j]);
+					psf_sndClose(ofd);					
+					cleanup(ifdlist);
+					return 1;
+				}
+			}
+			if(got==1){
+				p_filesamp = inframe;
+				for(k=0;k < inchans;k++)	//channel loop
+					*p_framesamp++	= *p_filesamp++;
+			}
+			else
+				p_framesamp += inchans;
+		}
+		
+		if(psf_sndWriteFloatFrames(ofd,outframe,1) < 0){
+			fprintf(stderr,"interlx: error writing to outfile\n");
+			psf_sndClose(ofd);            
+            cleanup(ifdlist);
+            return 1;
+		}
+        if(i % halfsec==0) {
+			printf("%.2lf secs\r",(double)i / (double) firstinprops.srate);
+            fflush(stdout);
+        }
+	}
+	printf("%.4lf secs\nWritten %ld sample frames to %s\n",(double)outframesize / (double)firstinprops.srate,outframesize,argv[1]);
+	if(psf_sndReadPeaks( ofd,fpeaks,&peaktime)){
+        printf("PEAK data:\n");
+        for(i = 0; i < firstinprops.chans; i++) {
+            double val, dbval;
+            val = (double) fpeaks[i].val;
+            dbval = 20.0 * log10(val);
+            printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+                   val,dbval,(unsigned int) fpeaks[i].pos,(double)fpeaks[i].pos / (double) firstinprops.srate);
+        }
+    }
+	
+	printf("\n");
+	psf_sndClose(ofd);
+	free(inframe);
+	free(outframe);
+    if(fpeaks)
+        free(fpeaks);
+	cleanup(ifdlist);
+    
+	return 0;
+}

+ 698 - 0
dev/externals/mctools/njoin.c

@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/* njoin.c: concantenate files with optional spacing */
+/* 12 Dec 2006 v 0.7: fixed bug in read_filelist: trap leading spaces on line */
+/* OCT 2009: v1.0 support tilde-prefixed path under unix */
+/* Jan 2010 v1.0.1 fixed bug processing lots of files and running out of portsf slots */
+/* Nov 2013 recognise MC_SURR_6_1 */
+/* Mar 2021  fix small file format type mismatch error (line 543 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <memory.h>
+#include <string.h>
+#include <assert.h>
+#ifdef unix
+#include <glob.h>
+#endif
+#include "portsf.h"
+
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+#define F_MAXLEN (1024) 
+/* For CERN will need to increase this a lot! */
+#define MAXFILES (512)
+
+
+enum {ARG_PROGNAME, ARG_FLIST, ARG_NARGS};
+enum {ARG_OUTFILE = ARG_NARGS};
+
+int read_filelist(FILE* ifp, char* p_flist[]);
+void cleanup(int ifd, int ofd,char* flist[], int nfiles);
+
+#ifdef unix
+char* CreatePathByExpandingTildePath(char* path)
+{
+    glob_t globbuf;
+    char **v;
+    char *expandedPath = NULL, *result = NULL;
+    
+    assert(path != NULL);
+    
+    if (glob(path, GLOB_TILDE, NULL, &globbuf) == 0) //success
+    {
+        v = globbuf.gl_pathv; //list of matched pathnames
+        expandedPath = v[0]; //number of matched pathnames, gl_pathc == 1
+        
+        result = (char*)calloc( strlen(expandedPath) + 1,sizeof(char)); //the extra char is for the null-termination
+        if(result)
+            strncpy(result, expandedPath, strlen(expandedPath) + 1); //copy the null-termination as well
+        
+        globfree(&globbuf);
+    }
+    
+    return result;
+}
+#endif
+
+void
+usage()
+{
+	fprintf(stderr,"\nCDP MCTOOLS: NJOIN v1.1.1 (c) RWD,CDP 2006,2010,2013,2021\n"
+			"concatenate multiple files into a single file\n"
+			"Usage: njoin [-sSECS | -SSECS][-cCUEFILE][-x] filelist.txt [outfile] \n"						
+			"       filelist.txt: text file containing list of sfiles\n"
+			"                     in order. One file per line. \n"
+			"                     Channel spec (if present) must be the same,\n"
+			"                     but files with no spec assumed compatible.\n"
+			"       -cCUEFILE   : if outfile used, generate cue textfile as CUEFILE.\n"
+			"       -sSECS      : separate files with silence of SECS seconds\n"
+			"       -SSECS      : as above, but no silence before first file.\n"
+			"                     Default: files are joined with no gap.\n"
+            "      -x           : strict: allow only CD-compatible files:\n"
+            "                     Must use sr=44100, minimum duration 4 secs.\n"
+			"       NB: Files must match sample rate and number of channels,\n"
+			"        but can have different sample types.\n"
+			"       Output sample format taken from file with highest precision.\n"
+			"       If no outfile given: program scans files and prints report.\n"
+#ifdef unix
+            "       Unix systems:  ~/ notation for home dir supported for file paths.\n"
+#endif
+			);	
+}
+
+void cleanup(int ifd, int ofd,char* flist[], int nfiles)
+{
+	int i;
+	for(i=0;i < nfiles; i++) {		
+		if(flist[i])
+			free(flist[i]);
+	}
+	if(ifd >=0)
+		psf_sndClose(ifd);
+	if(ofd >=0)
+		psf_sndClose(ofd);	
+}
+/*SHORT8,SHORT16,FLOAT32,INT_32,INT2424,INT2432,INT2024,INT_MASKED*/
+static int wordsize[] = {1,2,4,4,3,4,3};
+
+/*return 0 for props2 same or less, 1 for props2 higher*/
+int compare_precision(const PSF_PROPS* props1,const PSF_PROPS* props2)
+{
+	int retval = 0;
+	switch(props1->samptype){
+	case(PSF_SAMP_8):
+		if(props2->samptype != props1->samptype)
+			retval = 1;
+		break;
+	case(PSF_SAMP_16):
+		if(props2->samptype > props1->samptype)
+			retval = 1;
+		break;
+	case(PSF_SAMP_IEEE_FLOAT):
+		/* only higher prec is 32bit int */
+		if(props2->samptype== PSF_SAMP_32)
+			retval = 1;
+		break;
+	case(PSF_SAMP_32):
+		/* nothing higher than this!*/
+		break;
+	case(PSF_SAMP_24):
+	//case(INT2432): // NB illegal for almost all formats!
+	//case(INT2024):
+		if(props2->samptype == PSF_SAMP_IEEE_FLOAT || props2->samptype == PSF_SAMP_32)
+			retval = 1;
+		break;
+	default:  
+		break;
+	}
+	return retval;
+}
+
+const char* stype_as_string(const PSF_PROPS* props)
+{
+	const char* msg;
+	switch(props->samptype){
+	case(PSF_SAMP_8):
+		msg = "8-bit";
+		break;
+	case(PSF_SAMP_16):
+		msg = "16-bit";
+		break;
+	case(PSF_SAMP_IEEE_FLOAT):
+		msg = "32-bit floats";
+		break;
+	case(PSF_SAMP_32):
+		msg = "32-bit integer";
+		break;
+	case(PSF_SAMP_24):
+		msg = "24-bit";
+		break;
+	default:
+		msg = "unknown WAVE_EX sample size!";
+		break;
+	}
+	return msg;
+}
+//STDWAVE,MC_STD,MC_MONO,MC_STEREO,MC_QUAD,MC_LCRS,MC_BFMT,MC_DOLBY_5_1,MC_WAVE_EX 
+const char* chformat_as_string(const PSF_PROPS* props)
+{
+	const char* msg;
+	switch(props->chformat){
+	case MC_STD:
+		msg = "Generic WAVE-EX";
+		break;
+	case MC_MONO:
+		msg = "WAVE_EX Mono";
+		break;
+	case MC_STEREO:
+		msg = "WAVE_EX Stereo";
+		break;
+	case MC_QUAD:
+		msg = "WAVE_EX Quad";
+		break;
+	case MC_LCRS:
+		msg = "WAVE_EX LCRS Surround";
+		break;
+	case MC_BFMT:
+		msg = "WAVE_EX B-Format";
+		break;
+	case MC_DOLBY_5_1:
+		msg = "WAVE_EX Dolby 5.1";
+		break;
+	case MC_SURR_6_1:
+	    msg =  "6.1 surround";
+	    break;
+    case MC_SURR_5_0:
+        msg = "5.0 surround";
+        break;
+    case MC_SURR_7_1:
+        msg = "7.1 Surround";
+        break;
+    case MC_CUBE:
+        msg = "Cube Surround";
+        break;
+	case MC_WAVE_EX:
+		msg = "WAVE-EX Custom Multi-Channel";
+		break;
+    default:  // STDWAVE
+        msg = "Standard soundfile";
+        break;
+	}
+
+	return msg;
+}
+
+int read_filelist(FILE* ifp, char* p_flist[])
+{
+	char buf[F_MAXLEN];
+	long len;
+	int nfiles = 0;
+#ifdef _DEBUG
+	assert(ifp);
+	assert(p_flist);
+#endif
+	if(ifp==NULL || p_flist == NULL)
+		return -1;
+	while (fgets(buf,F_MAXLEN-1,ifp)){
+		char* pbuf = buf;
+		while(*pbuf == ' ')
+			pbuf++;
+		len = strlen(pbuf);
+		if(len > 1){	// line has at least a eol byte
+			p_flist[nfiles] = malloc(len+1);
+			strcpy(p_flist[nfiles],pbuf);
+			if(p_flist[nfiles][len-1] == 0x0A)
+				p_flist[nfiles][len-1] = '\0';
+			nfiles++;
+		}
+		if(feof(ifp))
+			break;
+		if(ferror(ifp))
+			return -1;
+	}	
+	return nfiles;
+}
+ 
+int strict_check(PSF_PROPS* props,unsigned long dur)
+{
+    int ret = 0;
+    unsigned long mindur = 4 * 44100;
+    
+    if(props->srate==44100 && dur >= mindur && props->chans==2)
+        ret = 1;
+    return ret;
+}
+
+int main(int argc, char* argv[])
+{
+	int i = 0,j,ofd = -1;
+	int ifd = -1;
+	char* flist[MAXFILES];
+	char* cuefilename = NULL;
+	FILE* cuefp = NULL;
+	int num_infiles = 0;
+	float *inframe = NULL;
+    float*space_frame = NULL;
+	PSF_PROPS inprops, thisinprops,outprops;
+	PSF_CHPEAK *fpeaks = NULL;
+	double space_secs = 0.0;
+	long space_frames = 0;
+    long thisdur = 0;
+	double totaldur = 0.0;
+	FILE* fp = NULL;
+	int formatsrc = 0;
+	unsigned int max_datachunk = 0xFFFFFFFFU - 1024U;   /* check Ok for PEAK chunk */
+	double maxdur;
+	double blockdur = 0.25;  /* match buffersize to srate, so we get tidy upodate msgs */
+	long buflen,block_frames;
+	unsigned long written;
+	int error = 0;
+	int do_process = 1;
+	int have_s = 0, have_S = 0;
+    int strict  =0;
+    int strict_failures = 0;
+    char* fname;
+
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.1.0\n");
+        return 0;
+    }
+    
+	if(argc < ARG_NARGS){
+		fprintf(stderr,"njoin: insufficient arguemnts\n");
+		usage();
+		return 1;
+	}
+	while(argv[1][0] =='-'){	
+		switch(argv[1][1]){
+		case('c'):
+			if(argv[1][2]== '\0'){
+				fprintf(stderr,"-c flag needs filename.\n");
+				return 1;
+			}
+			cuefilename = &(argv[1][2]);
+			break;
+		case('s'):
+			if(have_S){
+				fprintf(stderr,"njoin: cannot have both -s and -S.\n");
+				return 1;
+			}
+			space_secs = atof(&argv[1][2]);
+			if(space_secs < 0.0){
+				fprintf(stderr,"njoin: -tSECS cannot be negative!\n");
+				return 1;
+			}
+			have_s = 1;
+			break;
+		case('S'):
+			if(have_s){
+				fprintf(stderr,"njoin: cannot have both -s and -S.\n");
+				return 1;
+			}
+			space_secs = atof(&argv[1][2]);
+			if(space_secs < 0.0){
+				fprintf(stderr,"njoin: -tSECS cannot be negative!\n");
+				return 1;
+			}
+			have_S = 1;
+			break;
+        case 'x':
+            strict = 1;
+            break;
+		default:
+			fprintf(stderr,"\nnjoin: illegal flag option %s",argv[1]);
+			exit(1);
+		}
+		argc--; argv++;
+	}
+
+	if(argc < ARG_NARGS){
+		fprintf(stderr,"njoin: insufficient arguemnts\n");
+		usage();
+		return 1;
+	}
+	
+	if(argc==ARG_NARGS)
+		do_process = 0;
+	/********** READ filelist *********/
+
+	fp = fopen(argv[ARG_FLIST],"r");
+	if(fp==NULL){
+		fprintf(stderr,"njoin: Unable to open input file %s\n",argv[ARG_FLIST]);
+		return 1;
+	}
+	
+	memset(flist,0,MAXFILES * sizeof(char*));
+	num_infiles = read_filelist(fp, flist);
+	if(num_infiles < 0){
+		fprintf(stderr,"njoin: file error reading filelist %s\n",argv[ARG_FLIST]);
+		fclose(fp);
+		return 1;
+	}
+	if(num_infiles ==0){
+		fprintf(stderr,"njoin: filelist is empty!\n");
+		fclose(fp);
+		return 1;
+	}
+	if(num_infiles ==1){
+		fprintf(stderr,"njoin: only one file listed - nothing to do!\n");
+		fclose(fp);
+		return 1;
+	}
+	fclose(fp); fp = NULL;
+
+#ifdef _DEBUG
+	fprintf(stderr, "file list contains %d files: \n",num_infiles);	
+	for(i=0;i < num_infiles; i++)
+		fprintf(stderr,"%s\n",flist[i]);
+#endif
+
+	/********* open and check all soundfiles ***********/
+	fprintf(stderr,"checking files...\n");
+	
+	if(psf_init()){
+		fprintf(stderr,"njoin: startup failure.\n");
+		return 1;
+	}
+    i = 0;
+#ifdef unix
+    fname = CreatePathByExpandingTildePath(flist[i]);
+    /* must free pointer later */
+#else
+    fname = flist[i];
+#endif
+	//open first infile and get properties
+	ifd = psf_sndOpen(fname,&inprops,0);
+	if(ifd < 0){
+		fprintf(stderr,"unable to open infile %s.\n",fname);
+		cleanup(ifd,ofd,flist,num_infiles);
+		return 1;
+	}
+	thisdur = psf_sndSize(ifd);
+    if(strict){
+        if(!strict_check(&inprops,thisdur)){
+            fprintf(stderr,"Strict: file %s is not CD-compatible.\n",fname);
+            strict_failures++;
+        }
+    }
+	if(thisdur==0){
+		fprintf(stderr,"WARNING: file 1 empty: %s\n",fname);
+	}
+	else  {	
+		totaldur += (double) thisdur / inprops.srate;
+	}
+	psf_sndClose(ifd);
+#ifdef unix
+    free(fname);
+#endif
+	ifd = -1;
+	/* scan firther files, find max precision */
+	/* drop out if channel formats different */
+	for(i=1; i <	num_infiles; i++){
+#ifdef unix
+        fname = CreatePathByExpandingTildePath(flist[i]);
+        /* must free pointer later */
+#else
+        fname = flist[i];
+#endif
+        
+        
+		ifd = psf_sndOpen(fname,&thisinprops,0);
+		if(ifd < 0){
+			fprintf(stderr,"unable to open infile %s.\n",fname);
+			cleanup(ifd,ofd,flist,num_infiles);
+			exit(1);
+		}
+        thisdur = psf_sndSize(ifd);
+        if(strict){
+            if(!strict_check(&thisinprops,thisdur)){
+                fprintf(stderr,"Strict: file %s is not CD-compatible.\n",fname);
+                strict_failures++;
+            }
+        }
+		if(inprops.chans != thisinprops.chans){
+			fprintf(stderr,"njoin: channel mismatch in file %s",fname);
+			cleanup(ifd,ofd,flist,num_infiles);
+#ifdef unix
+            free(fname);
+#endif
+			return 1;
+		}
+		if(inprops.srate != thisinprops.srate){
+			fprintf(stderr,"njoin: sample rate mismatch in file %s",fname);
+			cleanup(ifd,ofd,flist,num_infiles);
+#ifdef unix
+            free(fname);
+#endif
+			return 1;
+		}
+		/* allow old multichannel files to be compatible with everything! */
+		if(! (inprops.chformat==(psf_channelformat)PSF_STDWAVE || thisinprops.chformat==(psf_channelformat)PSF_STDWAVE)){
+			if(inprops.chformat != thisinprops.chformat){
+				fprintf(stderr,"njoin: channel format mismatch in file %s",fname);
+				cleanup(ifd,ofd,flist,num_infiles);
+#ifdef unix
+                free(fname);
+#endif
+				return 1;
+			}
+		}
+		else {
+			/* one file is generic: promote format if possible*/
+			if(thisinprops.chformat > inprops.chformat)
+				inprops.chformat = thisinprops.chformat;
+		}
+
+		/* compare wordlength precision */
+		if(compare_precision(&inprops,&thisinprops)) {
+			inprops = thisinprops;
+			formatsrc = i;
+		}
+		thisdur = psf_sndSize(ifd);
+		if(thisdur==0){
+			fprintf(stderr,"WARNING: file %d empty: %s\n",i+1,fname);
+		}
+		else  {	
+			totaldur += (double) thisdur / thisinprops.srate;
+		}
+		psf_sndClose(ifd);
+		ifd = -1;
+#ifdef unix
+        free(fname);
+#endif
+	}
+    if(strict_failures){ 
+        fprintf(stderr,"Strict: %d files are CD-incompatible. Exiting.\n",strict_failures);
+        return 1;
+    }
+    
+	fprintf(stderr, "output format taken from file %d:\n\t%s\n",formatsrc+1,flist[formatsrc]);
+	fprintf(stderr, "sample type: %s\n",stype_as_string(&inprops));  
+	fprintf(stderr,"channel format: %s\n",chformat_as_string(&inprops));
+
+	maxdur = (double)(max_datachunk/ inprops.chans / wordsize[inprops.samptype]) / inprops.srate;
+	/*TODO: make sure we allow for size of PEAK chunk */
+	fprintf(stderr, "Max duration available for this format: %f secs.\n",maxdur);
+	if(have_S)
+		fprintf(stderr,"Total outfile length including spacing: %f secs\n", totaldur + (num_infiles-1) * space_secs);
+	else
+		fprintf(stderr,"Total outfile length including spacing: %f secs\n", totaldur + (num_infiles) * space_secs);
+
+	if(do_process == 0){
+		if(totaldur > maxdur)
+			fprintf(stderr, "Error: total duration exceeds capacity of file format.\n");
+		cleanup(ifd,ofd,flist,num_infiles);
+		return 0;
+	}
+
+	if(totaldur > maxdur){
+		fprintf(stderr, "Sorry! Total duration exceeds capacity of file format.\nProcess aborted.\n");
+		cleanup(ifd,ofd,flist,num_infiles);
+		return 1;
+	}
+    
+	/* if here, OK! We can make the file */
+    printf("processing files...\n");
+	outprops = inprops;
+	/* try to make a legal wave file! */
+	if((outprops.chans > 2 || outprops.samptype > PSF_SAMP_IEEE_FLOAT)
+		 && (outprops.format==PSF_STDWAVE))
+        outprops.chformat = /* PSF_WAVE_EX */ MC_STD;       //RWD 10:03:21
+    block_frames = (long)(blockdur * outprops.srate);
+	buflen = block_frames * outprops.chans;
+	inframe = malloc(buflen * sizeof(float));
+	if(inframe==NULL){
+		puts("No memory!\n");
+		cleanup(ifd,ofd,flist,num_infiles);
+		return 1;
+	}
+	//setup PEAK data
+	fpeaks = (PSF_CHPEAK *) calloc(outprops.chans,sizeof(PSF_CHPEAK));
+	if(fpeaks==NULL){
+		puts("njoin: error: no memory for internal PEAK buffer\n");
+		cleanup(ifd,ofd,flist,num_infiles);
+		return 1;
+	}
+
+	if(cuefilename){
+		cuefp = fopen(cuefilename, "w");
+		if(cuefp == NULL){
+			fprintf(stderr, "WARNING: unable to create cue file %s.\n",cuefilename);
+			cuefilename = NULL;
+		}
+	}
+
+    space_frame = calloc(sizeof(float),outprops.chans);
+    
+	ofd = psf_sndCreate(argv[ARG_OUTFILE],&outprops,0,0,PSF_CREATE_RDWR);
+	if(ofd < 0){
+		fprintf(stderr,"njoin: Cannot create outfile %s\n",argv[ARG_OUTFILE]);
+		cleanup(ifd,ofd,flist,num_infiles);
+		return 1;
+	}
+	fprintf(stderr, "generating outfile...\n");
+	written = 0;
+	if(cuefp) {
+		//fprintf(cuefp,"FILE %s WAVE\n",snd_getfilename(ofd));
+        fprintf(cuefp,"FILE %s WAVE\n",argv[ARG_OUTFILE]);
+		fprintf(cuefp,"\tTRACK 01 AUDIO\n");
+				fprintf(cuefp,"\t\tINDEX 01 00:00:00\n");
+	}
+	space_frames = (long) (space_secs * outprops.srate + 0.5);
+	/* add leading space ? */
+	if(have_s && space_frames > 0){
+		for(j=0; j < space_frames; j++) {
+			if(psf_sndWriteFloatFrames(ofd,space_frame,1) < 0){
+				fprintf(stderr,"njoin: error writing outfile\n");
+				cleanup(ifd,ofd,flist,num_infiles);
+				free(inframe);
+				free(fpeaks);
+				return 1;
+			}
+		}
+		written += space_frames;
+	}
+	for(i=0; i < num_infiles; i++){
+		long got, put;
+        PSF_PROPS fprops; // dummy - not needed 
+#ifdef unix
+        fname = CreatePathByExpandingTildePath(flist[i]);
+        /* must free pointer later */
+        /*RWD TODO: may fail with null return if file does not exist */
+#else
+        
+        fname = flist[i];
+#endif        
+		ifd = psf_sndOpen(fname,&fprops,0);
+		if(ifd < 0){
+			fprintf(stderr,"unable to open infile %s.\n",fname);
+			error++;
+			break;
+		} 
+        
+		do {			
+			got = psf_sndReadFloatFrames(ifd,inframe,block_frames);
+			if(got < 0){
+				fprintf(stderr,"njoin: error reading file %s\n",fname);
+				error++;
+				break;
+			}
+			
+			put = psf_sndWriteFloatFrames(ofd,inframe,got);
+			if(put != got){
+				fprintf(stderr,"njoin: error writing outfile\n");
+				error++;
+				break;
+			}
+			written += got;
+			fprintf(stderr,"%.2f\r",(double) written / outprops.srate);
+		} while (got > 0);
+		if(error)
+			break;
+		
+		/* add space */
+		if(i < num_infiles - 1){
+			/* update cue file */
+			if(cuefp){
+				double pos = (double)(psf_sndTell(ofd)) / outprops.srate;
+				int mins = (int)(pos / 60.0);
+				int secs = (int)(pos - mins);
+				int frames = (int) ((pos - (60.0 * mins + secs)) * 75.0);
+
+				fprintf(cuefp,"\tTRACK %.2d AUDIO\n",i+2);
+				fprintf(cuefp,"\t\tINDEX 01 %.2d:%.2d:%.2d\n",mins,secs,frames); 
+			}
+			
+			for(j=0; j < space_frames ; j++) {
+				if(psf_sndWriteFloatFrames(ofd,space_frame,1) < 0){
+					fprintf(stderr,"njoin: error writing outfile\n");
+					error++;
+					break;
+				}
+			}
+		}
+		if(error)
+			break;
+		written += space_frames;
+#ifdef unix
+        free(fname);
+#endif
+        /*RWD Jan 2010 MUST close the file or we may run out of portsf slots! */
+        psf_sndClose(ifd);
+        ifd = -1;
+	}
+
+	if(error){
+		fprintf(stderr,"Error: Outfile incomplete.\n");
+//		sndunlink(ofd);
+	}
+	else {
+		fprintf(stderr, "Done.\nWritten %ld frames to outfile\n",written);
+		if(psf_sndReadPeaks(ofd,fpeaks,NULL) > 0){
+            long i;
+            double peaktime;
+            printf("PEAK information:\n");	
+			for(i=0;i < inprops.chans;i++){
+                double val = fpeaks[i].val;
+				peaktime = (double) fpeaks[i].pos / (double) inprops.srate;
+                if(val==0.0)
+                    printf("CH %ld:\t%.4f           at %.4f secs\n", i+1, val,peaktime);
+                else
+                    printf("CH %ld:\t%.4f (%.2fdB) at %.4f secs\n", i+1, val, 20.0*log10(val),peaktime);
+			}
+        }
+	}
+	if(inframe)
+		free(inframe);
+	if(fpeaks)
+		free(fpeaks);
+	if(cuefp)
+		fclose(cuefp);
+	cleanup(ifd,ofd,flist,num_infiles);
+	psf_finish();
+	return 0;
+}

+ 333 - 0
dev/externals/mctools/nmix.c

@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The CDP System is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+//nmix.c
+//Oct 2009 updated to use portsf
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <sys/timeb.h>
+#include "portsf.h"
+
+#ifdef unix
+/* in portsf.lib */
+extern int stricmp(const char *a, const char *b);
+#endif
+
+//usage: nmix [-oOFFSET]  [-f] infile1 infile2 outfile
+void usage() {
+    printf("\nCDP MCTOOLS: NMIX V2.0.1 (c) RWD,CDP 1999,2009\n"
+           "mix two multi-channel files\n"
+           "usage:\n"
+           "nmix [-d][-f][-oOFFSET] infile1 infile2 outfile\n"
+           "     -d      : apply TPDF dither (16bit format output only).\n"
+           "     -f      : set output sample type to floats.\n"
+           "                Default: outfile type is that of infile 1\n"
+           "     -oOFFSET:  start infile2 at OFFSET seconds.\n"
+           "Files must have the same channel count.\n"
+           "WAVE-EX files must have the same speaker layout\n");
+
+    exit(0);
+}
+
+#define BUFLEN (1024)
+
+int main(int argc, char *argv[])
+{
+    int i,ifd1 = -1,ifd2=-1,ofd=-1;
+    int force_floats = 0;
+    int do_dither = 0;
+    float ampfac = 0.0;
+    long len_in1, len_in2,outlen;
+    double offset = 0.0;
+    long offsetframes = 0,framecount = 0;
+    long chans;
+    long sr;
+    long in1_sofar,in2_sofar;
+    int halfsec;
+    MYLONG peaktime;
+    PSF_PROPS props_in1,props_in2;
+    float *frame_in1 = NULL, *frame_in2 = NULL, *outframe = NULL;
+    PSF_CHPEAK *peaks = NULL;
+
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("2.0.1\n");
+        return 0;
+    }
+
+    if(argc < 4)
+        usage();
+
+    while(argv[1][0]=='-'){
+        char *valstr;
+        double val;
+        switch(argv[1][1]){
+        case 'd':
+            do_dither = 1;
+            break;
+        case('f'):
+            force_floats = 1;
+            break;
+        case('o'):
+            if(argv[1][2]=='\0'){
+                fprintf(stderr,"-o flag needs a number\n");
+                exit(1);
+            }
+            valstr = &argv[1][2];
+            val=atof(valstr);
+            if(val < 0.0){
+
+                fprintf(stderr,"offset must be >= 0\n");
+                exit(1);
+            }
+            if(val > 0.0)
+                offset = val;
+            break;
+
+        default:
+            fprintf(stderr,"incorrect flag option %c\n",argv[1][1]);
+            exit(1);
+        }
+        argc--; argv++;
+    }
+
+    if(argc < 4)
+        usage();
+    if(force_floats && do_dither)
+        fprintf(stderr,"Warning: dither option ignored for floats format.\n");
+
+    psf_init();
+
+    //open soundfiles: no auto-rescaling
+    if((ifd1 = psf_sndOpen(argv[1],&props_in1,0)) < 0){
+        fprintf(stderr,"Cannot open soundfile %s\n",argv[1]);
+        goto cleanup;
+    }
+
+    if((ifd2 = psf_sndOpen(argv[2],&props_in2,0)) < 0){
+        fprintf(stderr,"Cannot open soundfile %s \n",argv[2]);
+        goto cleanup;
+    }
+
+    if(props_in1.chans != props_in2.chans){
+        fprintf(stderr,"files do not have the same number of channels\n");
+        goto cleanup;
+    }
+
+    if(props_in1.srate != props_in2.srate){
+        fprintf(stderr,"files do not have the same sample rate\n");
+        goto cleanup;
+
+    }
+
+    if(props_in1.chformat != props_in2.chformat){
+        fprintf(stderr,"files do not have the same channel format\n");
+        goto cleanup;
+    }
+
+
+    sr = props_in1.srate;
+    chans  = props_in1.chans;
+    ampfac = 0.5f;                                  //just mixing 2 files...
+    if(offset > 0.0){
+        offsetframes = (long) (offset * (double) sr);
+    }
+    /* now we can set up frame arrays */
+
+    frame_in1 = (float *) calloc(chans, sizeof(float));
+    frame_in2 = (float *) calloc(chans, sizeof(float));
+    outframe = (float *) calloc(chans, sizeof(float));
+
+    if(frame_in1==NULL || frame_in2==NULL || outframe==NULL ){
+        puts("\nno memory for frame buffers");
+        goto cleanup;
+    }
+
+    len_in1 = psf_sndSize(ifd1);
+    if(len_in1==0){
+        fprintf(stderr,"infile %s is empty!\n",argv[1]);
+        goto cleanup;
+    }
+    len_in2 = psf_sndSize(ifd2);
+    if(len_in2==0){
+        fprintf(stderr,"infile %s is empty!\n",argv[2]);
+        goto cleanup;
+    }
+    if(len_in1 < 0){
+        fprintf(stderr,"system problem: cannot read size of infile %s\n",argv[1]);
+        goto cleanup;
+    }
+
+    if(len_in2 < 0){
+        fprintf(stderr,"system problem: cannot read size of infile %s\n",argv[2]);
+        goto cleanup;
+    }
+
+
+
+    outlen = len_in2 + offsetframes;
+    if(len_in1 > outlen)
+        outlen = len_in1;
+
+#ifdef _DEBUG
+    printf("DEBUG: outfile size expected to be %d frames\n",outlen);
+#endif
+    //setup PEAK data
+    peaks = (PSF_CHPEAK *) calloc(props_in1.chans,sizeof(PSF_CHPEAK));
+    if(peaks==NULL){
+        puts("nmix: error: no memory for internal PEAK buffer\n");
+        goto cleanup;
+    }
+    if(force_floats)
+        props_in1.samptype = PSF_SAMP_IEEE_FLOAT;
+
+
+    if(!is_legalsize(outlen,&props_in1)){
+        fprintf(stderr,"error: outfile size exceeds capacity of format.\n");
+        return 1;
+    }
+
+
+    if((ofd = psf_sndCreate(argv[3],&props_in1,0,0,PSF_CREATE_RDWR)) < 0){
+        fprintf(stderr,"unable to create outfile %s\n",argv[3]);
+        goto cleanup;
+    }
+    if(do_dither)
+        psf_sndSetDither(ofd,PSF_DITHER_TPDF);
+    halfsec = sr / 2;
+    //OK now we can do it....
+    printf("\nmixing....\n");
+
+    in1_sofar = in2_sofar = 0;
+    if(offsetframes > 0){
+        for(i=0;i < offsetframes; i++){
+            int got,j;
+            got = psf_sndReadFloatFrames(ifd1,frame_in1,1);
+            if(got != 1){
+                fprintf(stderr,"error reading from infile 1\n");
+                goto cleanup;
+            }
+            for(j=0;j < chans; j++) {
+                frame_in1[j] *= ampfac;
+            }
+            if((psf_sndWriteFloatFrames(ofd,frame_in1,1)) !=1){
+                fprintf(stderr,"\nerror writing to outfile\n");
+                goto cleanup;
+            }
+            if(framecount % halfsec==0)
+                printf("%.2lf secs\r",(double)framecount / (double) sr);
+
+            framecount++;
+        }
+    }
+    in1_sofar = offsetframes;
+    //now we are mixing two files...
+    for(i= offsetframes; i < outlen; i++){
+        int got, j;
+        //clear frame blocks
+        memset(frame_in1,0, chans * sizeof(float));
+        memset(frame_in2,0, chans * sizeof(float));
+        //if we  have data, fill frame and scale
+        if(in1_sofar < len_in1){
+            got = psf_sndReadFloatFrames(ifd1,frame_in1,1);
+            if(got != 1){
+                fprintf(stderr,"\nerror reading from infile 1\n");
+                goto cleanup;
+            }
+            in1_sofar++;
+            for(j=0;j < chans; j++)
+                frame_in1[j] *= ampfac;
+        }
+
+
+        if(in2_sofar < len_in2){
+            got = psf_sndReadFloatFrames(ifd2,frame_in2,1);
+            if(got != 1){
+                fprintf(stderr,"\nerror reading from infile 1\n");
+                goto cleanup;
+            }
+
+            in2_sofar++;
+
+            for(j=0;j < chans; j++)
+                frame_in2[j] *= ampfac;
+
+        }
+
+        //mix and write
+        for(j=0;j < chans; j++) {
+            outframe[j] = frame_in1[j] + frame_in2[j];
+
+        }
+        if(psf_sndWriteFloatFrames(ofd,outframe,1) < 0){
+            fprintf(stderr,"\nerror writing to outfile\n");
+            goto cleanup;
+        }
+        if(framecount % halfsec==0) {
+            printf("%.2lf secs\r",(double)framecount / (double) sr);
+            fflush(stdout);
+        }
+        framecount++;
+    }
+    printf("%.4lf secs\nWritten %ld sample frames to %s\n",(double)framecount / (double)sr,framecount,argv[3]);
+    if(psf_sndReadPeaks( ofd,peaks,&peaktime)){
+        printf("PEAK values:\n");
+        for(i=0; i < chans; i++){
+            double val, dbval;
+            val = (double) peaks[i].val;
+
+            if(val > 0.0){
+                dbval = 20.0 * log10(val);
+                printf("CH %d: %.6f (%.2lfdB) at frame %u:\t%.4f secs\n",i,
+                       val,dbval,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props_in1.srate);
+            }
+            else{
+                printf("CH %d: %.6f (-infdB) at frame %u:\t%.4f secs\n",i,
+                       val,(unsigned int) peaks[i].pos,(double)peaks[i].pos / (double) props_in1.srate);
+            }
+        }
+    }
+
+
+
+ cleanup:
+    if(ifd1 >=0)
+        psf_sndClose(ifd1);
+    if(ifd2 >=0)
+        psf_sndClose(ifd2);
+    if(ofd >=0)
+        psf_sndClose(ofd);
+    if(peaks)
+        free(peaks);
+    if(frame_in1 != NULL)
+        free(frame_in1);
+
+    if(frame_in2 != NULL)
+        free(frame_in2);
+    if(outframe != NULL)
+        free(outframe);
+
+
+    psf_finish();
+    return 0;
+}

+ 320 - 0
dev/externals/mctools/rmsinfo.cpp

@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+// rmsinfo
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <portsf.h>
+#include <math.h>
+#include <signal.h>
+#ifdef WIN32
+# if _MSC_VER  && _MSC_VER <= 1200
+# include <new.h>
+# endif
+#endif
+
+
+#ifdef unix
+/* in portsf.lib */
+extern "C" {
+    int stricmp(const char *a, const char *b);
+}
+#endif
+
+enum {ARG_NAME, ARG_INFILE,ARG_NARGS};
+
+enum {CH_RMS_POWER,CH_AMPSUM,CH_BISUM,CH_NORM_RMS,CH_NORM_AMPSUM};
+
+typedef struct {
+    double rmspower;
+    double abssum;
+    double bisum;
+    double norm_rms;
+    double norm_abssum;
+} CH_RMSINFO;
+
+#define BUFLEN (1024)
+
+static int scanning(1);
+
+void runhandler(int sig)
+{
+	if(sig == SIGINT){
+		scanning = 0;
+    }
+}
+
+void usage(){
+    printf("\nCDP MCTOOLS: RMSINFO v1.0.1 (c) RWD, CDP 2009\n");
+    printf("Scans infile and reports rms and average loudness (power) of infile,\n"
+           " relative to digital peak (0dBFS)\n"
+           );
+    printf("Usage: rmsinfo [-n] infile [startpos [endpos]]\n"
+           "Standard output shows:\n"
+           "     RMS level\n"
+           "     Average level\n"
+           "     DC level (bipolar average)\n"
+           "-n : Include equivalent 0dBFS-normalised RMS and AVG levels.\n"
+           );
+    printf("Optional arguments:\n"
+           "startpos  :  start file scan from <startpos> seconds.\n"
+           "endpos    :  finish file scan at <endpos> seconds.\n"
+           );
+    printf("To stop a scan early, use CTRL-C.\n"
+           "Program will report levels up to that point.\n\n"
+           );
+}
+#ifdef WIN32
+#if _MSC_VER  && _MSC_VER <= 1200
+
+ int newhandler(size_t size);
+ class bad_alloc{};
+ int newhandler(size_t size)
+ {
+     throw bad_alloc();
+ }
+#endif
+#endif
+
+
+
+int main(int argc, char**argv)  {
+    long inframes,framesread=0,total_framesread;
+    double maxsamp = 0.0,startpos = 0.0,endpos;
+    long startframe = 0,endframe;
+    long halfsecframes = 0;
+    int i,j,ifd = -1;
+    int chans;
+    int do_norm = 0;
+	PSF_PROPS inprops;
+    CH_RMSINFO* rmsinfo = NULL;
+    double* rmsfac  = 0;
+    double* ampsum  = 0;
+    double* ampsumb = 0;
+    double* inbuf   = 0;
+    double* nrmsfac = 0;
+    double* nampsum = 0;
+    
+    
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("1.0.1\n");
+        return 0;
+    }
+#ifdef WIN32    
+# if _MSC_VER  && _MSC_VER <= 1200
+     _set_new_handler( newhandler );
+# endif
+#endif
+    if(psf_init()){
+		puts("unable to start portsf\n");
+		return 1;
+	}
+    if(argc < 2){		 
+		usage();
+		return(1);
+	}
+    while(argv[1][0]=='-'){
+		switch(argv[1][1]){
+        case 'n':
+            do_norm = 1;
+            break;
+        default:
+            fprintf(stderr, "Unrecognised flag option %s\n",argv[1]);
+            return 1;
+        }
+        argc--; argv++;
+    }
+    if(argc < 2){		 
+		usage();
+		return(1);
+	}
+    if((ifd = psf_sndOpen(argv[ARG_INFILE],&inprops, 0)) < 0){
+		fprintf(stderr,"\nUnable to open input soundfile %s",argv[ARG_INFILE]);
+		return(1);
+	}
+	inframes = psf_sndSize(ifd);  // m/c frames
+    endframe = inframes;
+    
+	if(inframes <= 0)
+        return 0;
+	if(argc >= 3) {
+        long lpos;
+        startpos = atof(argv[ARG_INFILE+1]);
+        if(startpos < 0.0){
+            fprintf(stderr,"Error: startpos must be positive\n");
+            return 1;
+        }
+        lpos = (long)( startpos * inprops.srate);
+        if(lpos > inframes){
+            fprintf(stderr,"Error: startpos value beyond end of file.\n");
+            return 1;
+        }
+        startframe = lpos;
+    }
+    if(argc >= 4) {
+        long lpos;
+        endpos = atof(argv[ARG_INFILE+2]);
+        
+        lpos = (long)(endpos * inprops.srate);
+        if(lpos > inframes){
+            fprintf(stderr,"Warning: endpos value too large - reset to end of file.\n");
+            return 1;
+        }
+        endframe = lpos;
+        if(!(endframe > startframe)){
+            fprintf(stderr,"Error: endpos must be beyond startpos.\n");
+            return 1;
+        }
+    }
+    if(startframe)
+        printf("Starting at frame %ld, ending at frame %ld\n",startframe, endframe);
+    
+    chans   = inprops.chans;
+    try {
+        inbuf   = new double[BUFLEN * chans];
+        rmsinfo = new CH_RMSINFO[chans];
+        rmsfac  = new double[chans];
+        ampsum  = new double[chans];
+        ampsumb = new double[chans];
+        nrmsfac = new double[chans];
+        nampsum = new double[chans];
+    }
+    catch(...){
+        fputs("no memory!\n",stderr);
+        return 1;
+    }
+    for(i=0; i < chans; i++){
+        rmsfac[i]  = 0.0;
+        ampsum[i]  = 0.0;
+        ampsumb[i] = 0.0;
+        nrmsfac[i] = 0.0;
+        nampsum[i] = 0.0;
+    }
+    halfsecframes = inprops.srate / 2; 
+    signal(SIGINT,runhandler);
+    long wanted = endframe - startframe;
+    printf("Scanning %ld frames (%.3lf secs):\n",wanted, (double)wanted / inprops.srate);
+    total_framesread = 0;
+    if(startframe) {
+        if(psf_sndSeek(ifd,startframe,PSF_SEEK_SET)){
+            fprintf(stderr,"File Seek error.\n");
+            return 1;
+        }
+    }
+        
+	while((framesread = psf_sndReadDoubleFrames(ifd,inbuf,BUFLEN)) > 0){
+        double fval;
+        for(i = 0;i < framesread;i++) {
+            for(j = 0; j < chans; j++){
+                double val = inbuf[i*chans + j];
+                fval = fabs(val);
+                maxsamp = fval >  maxsamp ? fval : maxsamp;
+                ampsum[j]   += fval;
+                rmsfac[j]   += val*val; 
+                ampsumb[j]  += val;
+            }
+            total_framesread++;
+            if(scanning==0)
+                break;
+            if(total_framesread == wanted) 
+                break;
+            if((total_framesread % halfsecframes) == 0){
+                printf("%.2lf\r",total_framesread / (double) inprops.srate);
+                fflush(stdout);
+            }
+        }
+        if(total_framesread == wanted) {
+            break;
+        }
+    }
+    if(framesread < 0){
+        fprintf(stderr,"Error reading file.\n");
+        return 1;
+    }
+    for(i=0;i < chans;i++){
+        rmsfac[i]  /= total_framesread;
+        rmsfac[i]   = sqrt(rmsfac[i]);
+        ampsum[i]  /= total_framesread;
+        ampsumb[i] /= total_framesread;
+    }
+
+    double normfac = 1.0 / maxsamp;
+    if(scanning==0)
+        printf("\nScan stopped.\n");
+    if(total_framesread < inframes){
+        printf("Scanned %ld frames (%.2lf secs).\n",total_framesread,total_framesread / (double)inprops.srate);
+    }
+    
+    printf("Maximum sample = %lf (%.2lfdB)\n",maxsamp,20.0 * log10(maxsamp));
+    printf("Maximum normalisation factor = %.4f\n",normfac);
+    
+    for(i=0;i < chans;i++){
+        rmsinfo[i].rmspower    = rmsfac[i];
+        rmsinfo[i].abssum      = ampsum[i];
+        rmsinfo[i].bisum       = ampsumb[i];
+        rmsinfo[i].norm_rms    = normfac * rmsfac[i];
+        rmsinfo[i].norm_abssum = normfac * ampsum[i];
+    }
+    if(do_norm){
+        printf("\t   RMS LEVEL\t    AVG  \t   NET DC\t   NORM RMS\t  NORM AVG\n");
+        printf("CH\t AMP\t DB\t AMP\t DB\t AMP\t DB\t AMP\t DB\t AMP\t DB     \n");
+    }
+    else{
+        printf("\t   RMS LEVEL\t    AVG  \t   NET DC\n");
+        printf("CH\t AMP\t DB\t AMP\t DB\t AMP\t DB\n"); 
+    }
+    for(i=0;i < chans;i++){
+        double d1,d2,d3,d4,d5;
+        
+        d1 = 20*log10(rmsfac[i]);
+        d2 = 20*log10(ampsum[i]);
+        d3 = 20*log10(fabs(ampsumb[i]));
+        d4 = 20*log10(normfac * rmsfac[i]);
+        d5 = 20*log10(normfac * ampsum[i]);
+        if(do_norm){
+            printf("%d\t%.5lf\t%.2lf\t%.5lf\t%.2lf\t%+.4lf\t%.2lf\t%.5lf\t%.2lf\t%.5lf\t%.2lf\n",i+1,
+               rmsinfo[i].rmspower,d1,
+               rmsinfo[i].abssum,d2,
+               rmsinfo[i].bisum,d3,
+               rmsinfo[i].norm_rms,d4,
+               rmsinfo[i].norm_abssum,d5
+            );
+        }
+        else {
+            printf("%d\t%.5lf\t%.2lf\t%.5lf\t%.2lf\t%+.4lf\t%.2lf\n",i+1,
+                   rmsinfo[i].rmspower,d1,
+                   rmsinfo[i].abssum,d2,
+                   rmsinfo[i].bisum,d3
+            );
+        }
+    }
+        
+    delete [] inbuf;
+    delete [] rmsfac;
+    delete [] ampsum;
+    delete [] ampsumb;
+    delete [] rmsinfo;
+    psf_sndClose(ifd);
+    psf_finish();
+
+	return 0;
+}

+ 378 - 0
dev/externals/mctools/sfprops.c

@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
+ * http://people.bath.ac.uk/masrwd
+ * http://www.composersdesktop.com
+ * This file is part of the CDP System.
+ * The CDP System is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation; either 
+ * version 2.1 of the License, or (at your option) any later version. 
+ *
+ * The CDP System is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the CDP System; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ 
+/* sfprops.c: display primary soundfile properties 
+ * uses sfsysEx.lib: recognizes WAVE-EX formats
+ * part of the CDP MCTOOLS suite
+ */
+//RWD.6.99 use new funcs to report 24bit formats, etc
+//last update: 22.6.99 enumerate PEAK chans from 1, link with latest sfsysEx
+/* Nov28 2001: rebuild with sfsysEx recognizing stupid QuickTime AIFC floats with 16bit size! */
+/*Dec 2005 support .amb extension */
+/*April 2006: build with updated sfsys to read PEAK chunk after data chunk (Thanks to Sony!)*/
+/* OCt 2009 TODO: sort out 64bit platform issues (peaktime etc) */
+/* FEB 2010: decl filesize etc as unsigned to read huge file sizes! */
+/* Nov 2013 added MC_SURR_6_1 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+#include <sfsys.h>
+#include <chanmask.h>
+
+#ifdef unix
+
+int stricmp(const char *a, const char *b)
+{
+    while(*a != '\0' && *b != '\0') {
+        int ca = islower(*a) ? toupper(*a) : *a;
+        int cb = islower(*b) ? toupper(*b) : *b;
+        
+        if(ca < cb)
+            return -1;
+        if(ca > cb)
+            return 1;
+        
+        a++;
+        b++;
+    }
+    if(*a == '\0' && *b == '\0')
+        return 0;
+    if(*a != '\0')
+        return 1;
+    return -1;
+}
+#endif
+
+typedef struct wave_ex_speaker {
+    int mask;
+    char name[28];
+} WAVE_EX_SPEAKER;
+
+
+static const WAVE_EX_SPEAKER speakers[NUM_SPEAKER_POSITIONS] = {
+    {SPEAKER_FRONT_LEFT,"Front Left"},
+    {SPEAKER_FRONT_RIGHT,"Front Right"},
+    {SPEAKER_FRONT_CENTER,"Front Centre"},
+    {SPEAKER_LOW_FREQUENCY,"Low Frequency"},
+    {SPEAKER_BACK_LEFT,"Back Left"},
+    {SPEAKER_BACK_RIGHT,"Back Right"},
+    {SPEAKER_FRONT_LEFT_OF_CENTER,"Front Centre-Left"},
+    {SPEAKER_FRONT_RIGHT_OF_CENTER,"Front Centre-Right"},
+    {SPEAKER_BACK_CENTER,"Back Centre"},
+    {SPEAKER_SIDE_LEFT,"Side Left"},
+    {SPEAKER_SIDE_RIGHT,"Side Right"},
+    {SPEAKER_TOP_CENTER,"Top Centre"},
+    {SPEAKER_TOP_FRONT_LEFT,"Front Top Left"},
+    {SPEAKER_TOP_FRONT_CENTER,"Front Top Centre"},
+    {SPEAKER_TOP_FRONT_RIGHT,"Front Top Right"},
+    {SPEAKER_TOP_BACK_LEFT,"Back Top Left"},
+    {SPEAKER_TOP_BACK_CENTER,"Back Top Centre"},
+    {SPEAKER_TOP_BACK_RIGHT,"Back Top Right"}
+};
+
+void usage(){
+    fprintf(stderr,"CDP MCTOOLS: SFPROPS v2.2.0 (c) RWD,CDP,1999,2009,2010,2013\n"
+                    "Display soundfile details, with WAVE-EX speaker positions\n"
+                    "\n\tusage: sfprops infile\n");
+}
+
+ 
+
+int main(int argc, char **argv)
+{
+
+    int i,ifd;
+    unsigned int nframes,filesize; /* FEB 2010 */
+    double srate;
+    SFPROPS props = {0};
+    const char *name = NULL;
+    CHPEAK *peaks = NULL;
+    int res,peaktime,speakermask = 0;
+    float fmaxamp;
+    int lmaxamp;
+    
+    /* CDP version number */
+    if(argc==2 && (stricmp(argv[1],"--version")==0)){
+        printf("2.2.0.\n");
+        return 0;
+    }
+    
+    if(argc< 2){
+        usage();
+        exit(1);
+    }
+    if(sflinit("sfprops")){
+        fprintf(stderr,"SFPROPS: unable to initialize CDP Sound Filing System\n");
+        exit(1);
+    }
+    if((ifd = sndopenEx(argv[1],0,CDP_OPEN_RDONLY)) < 0){
+        fprintf(stderr,"SFPROPS: unable to open infile %s: %s\n",argv[1], sferrstr());
+        exit(1);
+    }
+
+    if(!snd_headread(ifd,&props)){
+        fprintf(stderr,"SFPROPS: unable to read infile header\n");
+        exit(1);
+    }
+
+    srate = (double) props.srate;
+    filesize = sndsizeEx(ifd);
+    nframes = filesize/ props.chans;        /*assume soundfile for now */
+    name = snd_getfilename(ifd);
+    printf("Properties of %s:\n",name);
+    printf("File type:  ");
+    switch(props.type){
+    case(wt_wave):
+        printf("soundfile\nFormat         :  ");
+
+        switch(props.format){
+        case(WAVE):
+            printf("Standard WAVE format\n");
+            break;
+        case(WAVE_EX):
+            printf("MS WAVE-FORMAT-EXTENSIBLE\n");
+            printf("SPEAKER CONFIGURATION:\t");
+
+            switch(props.chformat){
+            //case(MC_STD):
+            //  printf("unassigned (generic format)");
+            //  break;
+            case(MC_MONO):
+                printf("Mono\n");
+                break;
+            case(MC_STEREO):
+                printf("Stereo\n");
+                break;
+            case(MC_QUAD):
+                printf("Rectangular Quad\n");
+                break;
+            case(MC_LCRS):
+                printf("Quad Surround\n");
+                break;
+            case(MC_BFMT):
+                printf("Ambisonic B-Format\n");
+                break;
+            case(MC_DOLBY_5_1):
+                printf("5.1 (Dolby) Surround\n");
+                break;
+            case(MC_SURR_6_1):
+                printf("6.1 Surround\n");
+                break;
+            case(MC_SURR_7_1):
+                printf("7.1 Surround\n");
+                break;
+            case(MC_CUBE):
+                printf("Cube Surround\n");
+                break;
+            default:
+                printf("Special speaker assignments\n");
+                break;
+            }
+            speakermask = sndgetchanmask(ifd);
+            if(speakermask < 0)
+                fprintf(stderr,"Unable to read speakermask from WAVE_EX header\n");
+            else {
+                //try to figure out the mask
+                int assigned = 0;
+                int shift = 0;
+                int this_channel = 1;
+                printf("Speaker Mask = %d (0x%x)\n",speakermask,(unsigned int) speakermask);
+                while(assigned < props.chans){
+                    if(speakers[shift].mask & speakermask){
+                        printf("Channel %d: %s\n",this_channel++,speakers[shift].name);
+                        assigned++;
+                    }
+                    if(++shift == NUM_SPEAKER_POSITIONS)
+                        break;
+                }
+                if(assigned < props.chans)
+                    printf("Remaining channels not assigned speaker locations.\n");
+
+            }
+            break;
+                
+        case(AIFF):
+            printf("AIFF format\n");
+            break;
+        case(AIFC):
+            printf("AIFC format\n");
+            break;
+        default:
+            printf("unknown format\n");
+            break;
+        }
+        printf("Sample Rate    :  %d\n",props.srate);
+        printf("Channels       :  %d\n",props.chans);
+        printf("Sample Frames  :  %d\n",nframes);
+        printf("sample type:   :  ");
+        switch(props.samptype){
+        case(SHORT8):
+            printf("8-bit\n");
+            break;
+        case(SHORT16):
+            printf("16-bit\n");
+            break;
+        case(FLOAT32):
+            printf("32bit floats\n");
+            break;
+        case(INT_32):
+            printf("32bit (integer)\n");
+            break;
+        case(INT2424):
+            printf("24bit (packed)\n");
+            break;
+        case(INT2432):
+            printf("24bit in 32bit words\n");
+            break;
+        case(INT2024):
+            printf("20bit in 24bit words\n");
+            break;
+        case(INT_MASKED):
+            printf("non-standard WAVE_EX format\n");
+            //fet more info....
+            break;
+        default:
+            printf("sorry: don't recognize word format!\n");
+            break;
+
+        }
+        printf("duration       :  %.4lf secs\n",(double)nframes / srate);
+        //this is the problem: we never decided what type maxamp is, officially!
+        if(props.samptype==FLOAT32){
+            if(sndgetprop(ifd,"maxamp",(char *)&fmaxamp,sizeof(float)) == sizeof(float)){
+                printf("CDP maxamp     :  %.4lf\n",fmaxamp);    
+            }
+        }
+        else{
+            if(sndgetprop(ifd,"maxamp",(char *)&lmaxamp,sizeof(int)) == sizeof(int)){
+                printf("CDP maxamp     :  %d\n",lmaxamp);   
+            }
+        }
+        peaks = (CHPEAK *) calloc(props.chans,sizeof(CHPEAK));
+        if(peaks==NULL){
+            puts("sfprops: no memory for fpeak data buffer\n");
+            exit(1);
+        }
+        else{
+            time_t thistime;
+            res = sndreadpeaks(ifd,props.chans,peaks, (int *) &peaktime);
+            thistime = (time_t) peaktime;
+            if(res ==0)
+                printf("no peak data in this infile\n");
+            else if(res < 0){
+                fprintf(stderr,"sfprops: WARNING: error reading infile peak data\n");
+                
+            }
+            else {      
+                printf("PEAK data:\n\tcreation time: %s\n", ctime(&thistime));
+                //for(i=0;i < props.chans; i++)
+                //  printf("CH %d: %.4lf at frame %d:\t%.4lf secs\n",
+                //  i+1,peaks[i].value,peaks[i].position,(double) (peaks[i].position) / srate);
+                for(i=0; i < props.chans; i++){
+                    double val, dbval;
+                    val = (double) peaks[i].value;
+                    
+                    if(val > 0.0){
+                        dbval = 20.0 * log10(val);
+                        printf("CH %d: %.6f (%.2lfdB) at frame %9d:\t%.4f secs\n",i,
+                               val,dbval,peaks[i].position,(double)(peaks[i].position / (double) srate));
+                    }
+                    else{
+                        printf("CH %d: %.6f (-infdB)  \t\t:\t%.4f secs\n",
+                               i,
+                               val, (double)(peaks[i].position / (double) srate)); 
+                    }
+                }
+            }
+        }
+        
+        break;
+    case(wt_analysis):
+        printf("CDP pvoc analysis file.\n");
+        printf("Channel Format:       Amplitude,Frequency\n");
+        printf("Orig rate:            %d\n",props.origrate);
+        printf("Analysis Window Size: %d\n",props.winlen);
+        printf("Analysis channels:    %d\n",props.chans/2);
+        printf("Window Overlap:       %d\n",props.decfac);
+        printf("Analysis rate:        %.4f\n",props.arate);
+        printf("Frame count:          %d\n",filesize / (props.chans));
+        printf("Data size (floats):   %d\n",filesize);
+        printf("Duration (secs):      %.3lf\n",
+            ((filesize / props.chans) * props.decfac) / (double) props.origrate);
+        break;
+    case(wt_formant):
+        printf("CDP formant data\n");
+        printf("Specenvcnt:           %d\n",props.specenvcnt);
+        printf("Analysis Window Size: %d\n",props.winlen);
+        printf("Channels:             %d\n",props.chans);
+        printf("Frame count:          %d\n",filesize);
+        printf("Orig rate:            %d\n",props.origrate);        
+        printf("Window Overlap:       %d\n",props.decfac);
+        printf("Analysis rate:        %.4f\n",props.arate);
+        printf("Orig Chans:          %d\n",props.origchans);        
+        printf("Duration (secs):      %.3lf\n",(filesize /props.specenvcnt)/ props.arate );
+        break;
+    case(wt_transposition):
+        printf("CDP transposition data\n");
+        printf("Orig sample rate:     %d\n",props.origrate);
+        printf("Analysis Window Size: %d\n",props.winlen);
+        printf("Channels:             %d\n",props.chans);
+        printf("Window Overlap:       %d\n",props.decfac);
+        printf("Analysis rate:        %.4f\n",props.arate);
+        printf("Orig Chans:          %d\n",props.origchans);
+        printf("Data size (floats):   %d\n",filesize);
+        printf("Duration (secs):      %.3lf\n",
+            ((filesize / props.chans) * props.decfac) / (double) props.origrate);
+        break;
+    case(wt_pitch):
+        printf("CDP pitch data\n");
+        printf("Orig sample rate:     %d\n",props.origrate);
+        printf("Analysis Window Size: %d\n",props.winlen);
+        printf("Channels:             %d\n",props.chans);
+        printf("Window Overlap:       %d\n",props.decfac);
+        printf("Analysis rate:        %.4f\n",props.arate);
+        printf("Orig Chans:          %d\n",props.origchans);
+        printf("Data size (floats):   %d\n",filesize);
+        printf("Duration (secs):      %.3lf\n",
+            ((filesize / props.chans) * props.decfac) / (double) props.origrate);
+        break;
+    case(wt_binenv):
+        printf("CDP binary envelope data\n");
+        printf("envelope window size: %f msecs\n",props.window_size);
+        printf("sample rate:          %d\n",props.srate);
+        printf("Channels:             %d\n",props.chans);
+        printf("Points:               %d\n",filesize);
+        printf("Duration (secs):      %.3f\n",filesize * (props.window_size * 0.001));
+        break;
+    default:
+        printf("internal error! unlisted soundfile type\n");
+        break;
+    }
+
+    sndcloseEx(ifd);
+//  sffinish();
+    return 0;
+}
+
+
+