Browse Source

long->int conversions, remove warnings

richarddobson 2 years ago
parent
commit
9f159c874d
1 changed files with 588 additions and 589 deletions
  1. 588 589
      dev/modify/gain.c

+ 588 - 589
dev/modify/gain.c

@@ -1,589 +1,588 @@
-/*
- * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
- * http://www.trevorwishart.co.uk
- * 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
- *
- */
-
-
-
-/* floatsam version*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <structures.h>
-#include <tkglobals.h>
-#include <cdpmain.h>
-#include <modify.h>
-#include <modeno.h>
-#include <globcon.h>
-#include <modify.h>
-
-#include <sfsys.h>
-
- /* RWD added do_clip, peak (later, sort out nChans PEAK stuff... */
-static void gain(long samples,double multiplier,double maxnoclip,long *numclipped,
-				 int do_clip,double *peak,dataptr dz);
-static int find_max(double *maxfound,dataptr dz);
-static int  find_maximum(int infile,long *maxloc,long *maxrep,double *maxsamp,dataptr dz);
-static void	get_max(double *,long,long,long *,long *,dataptr dz);
-static int  balance(double mratio,dataptr dz);
-//TW replaced by peakchunk
-//static int	write_maxsamp_properties(double,long,long,dataptr dz);
-static int  do_balance(dataptr dz);
-static int  gain_process(dataptr dz);
-static int  get_normalisation_gain(dataptr dz);
-static void do_normalise(dataptr dz);
-static void do_phase_invert(dataptr dz);
-static void find_maxsamp(double *maxfound,dataptr dz);
-static int  do_multifile_loudness(dataptr dz);
-
-
-#define	MAX_DBGAIN	 (90)
-
-//TW UPDATE: further updated for floatsams and new-style clipping detection
-int gainenv(long samples,long *last_total,double maxnoclip,long *numclipped,int do_clip,double *peak,dataptr dz);
-
-/************************** LOUDNESS_PROCESS *******************************/
-
-int loudness_process(dataptr dz)
-{
-	long n, m;
-	double maxtime,intime, ratio;  /*RWD April 2004 needed to add these  */ 
-	switch(dz->mode) {
-	case(LOUD_PROPOR):
-	case(LOUD_DB_PROPOR):
-		maxtime = dz->brk[LOUD_GAIN][(dz->brksize[LOUD_GAIN] - 1) * 2];
-		intime = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
-		ratio = intime/maxtime;
-		for(n=0,m = 0;n < dz->brksize[LOUD_GAIN];n++,m+=2)
-			dz->brk[LOUD_GAIN][m] = dz->brk[LOUD_GAIN][m] * ratio;
-		dz->mode = LOUDNESS_GAIN;
-		break;
-	case(LOUDNESS_DBGAIN):
-		if(dz->brksize[LOUD_GAIN]) {
-			for(n=0,m=1;n < dz->brksize[LOUD_GAIN];n++,m+=2)
-				dz->brk[LOUD_GAIN][m] = dbtogain(dz->brk[LOUD_GAIN][m]);
-		} else {
-			dz->param[LOUD_GAIN] = dbtogain(dz->param[LOUD_GAIN]);
-		}
-		break;
-	}
-	switch(dz->mode) {
-	case(LOUDNESS_LOUDEST):
-	case(LOUDNESS_EQUALISE): 	return do_multifile_loudness(dz);
-	case(LOUDNESS_BALANCE): 	return do_balance(dz);
-	default:				 	return gain_process(dz);
-	}
-	return(FINISHED);	/* NOTREACHED */
-}
-
-/************************** GAIN_PROCESS *******************************/
-
-int gain_process(dataptr dz)
-{
-	int exit_status;
-	double maxnoclip = F_MAXSAMP, peakval = 0.0;
-//TW UPDATE
-	long numclipped = 0, last_total = 0;
-	int clipsamps = 1;
-	float *buffer = dz->sampbuf[0];
-
-	if(dz->true_outfile_stype == SAMP_FLOAT)
-		if(dz->clip_floatsams == 0)
-			clipsamps = 0;
-
-	switch(dz->mode) {
-	case(LOUDNESS_NORM):
-	case(LOUDNESS_SET):
-		if((exit_status = get_normalisation_gain(dz))!=CONTINUE)
-			return(exit_status);
-		break;
-	}
-	display_virtual_time(0,dz);
-	while(dz->samps_left > 0) {
-		if((exit_status = read_samps(buffer,dz))<0) {
-			sprintf(errstr,"Cannot read data from sndfile.\n");
-			return(PROGRAM_ERROR);
-		}
-		switch(dz->mode) {
-		case(LOUDNESS_GAIN):
-		case(LOUDNESS_DBGAIN):
-//TW UPDATE >>
-			if(dz->brksize[LOUD_GAIN])
-				gainenv(dz->ssampsread,&last_total,maxnoclip,&numclipped,clipsamps,&peakval,dz);
-			else if(dz->param[LOUD_GAIN] <= FLTERR) {
-				sprintf(errstr,"With gain of %lf the soundfile will be reduced to SILENCE!\n",dz->param[LOUD_GAIN]);
-				return(DATA_ERROR);
-			} else
-//<< TW UPDATE
-				gain(dz->ssampsread,dz->param[LOUD_GAIN],maxnoclip,&numclipped,clipsamps,&peakval,dz);
-			break;
-		case(LOUDNESS_NORM):
-		case(LOUDNESS_SET):
-			do_normalise(dz);
-			break;
-		case(LOUDNESS_PHASE):
-			do_phase_invert(dz);
-			break;
-		}
-		if(dz->ssampsread > 0) {
-			if((exit_status = write_exact_samps(buffer,dz->ssampsread,dz))<0)
-				return(exit_status);
-		}
-	}
-	if(clipsamps && (numclipped > 0))
-		sprintf(errstr, "WARNING: %ld samples were clipped.\n", numclipped);
-	dz->peak_fval = peakval;
-	/*will get written to header automatically*/
-	return(FINISHED);
-}
-
-/************************** GAIN *******************************/
-
-void gain(long samples,double multiplier,double maxnoclip,long *numclipped,
-		  int do_clip,double *peak,dataptr dz)
-{
-	long i;            
-	double s, buf_peak = *peak;
-	float *buffer = dz->sampbuf[0];
-	if(multiplier < 0.0) 
-		multiplier = -multiplier;
-	for(i = 0; i < samples; i++) {
-		s = buffer[i] * multiplier;
-		if(s >= 0) {
-			if(do_clip && (s > maxnoclip)) {
-				(*numclipped)++;
-				s = F_MAXSAMP;
-			}
-			buf_peak = max(buf_peak,s);
-		} else {
-			if(do_clip && (-s > maxnoclip)) {
-				(*numclipped)++;
-				s = -F_MAXSAMP;
-			}
-			buf_peak = max(buf_peak,-s);
-		}
-		buffer[i] = (float) s;
-		*peak = buf_peak;
-	}
-	
-}
-
-/**************************** DO_NORMALISE ***************************/
-/* RWD NB my old floatsam version added a peak_val arg */
-void do_normalise(dataptr dz)
-{   
-	register long i;
-
-	float *buffer = dz->sampbuf[0];
-	float dgain = (float) dz->param[LOUD_GAIN];
-    for(i = 0; i < dz->ssampsread; i++) {
-//TW	float sampl;
-//TW   	sampl  = buffer[i] * dgain;
-//TW   	buffer[i] =  sampl;
-//TW must cast to float anyway, as multiply gives double
-	   	buffer[i] =  (float)(buffer[i] * dgain);
-    }
-}
-
-/**************************** DO_PHASE_INVERT ***************************/
-
-void do_phase_invert(dataptr dz)
-{   register long i;
-	double samplong;
-	float *buffer = dz->sampbuf[0];
-    for(i = 0; i < dz->ssampsread; i++) {
-    	samplong  = -buffer[i];
-		samplong = min(samplong,(double)F_MAXSAMP);
-    	buffer[i] = (float)(samplong);
-    }
-}
-
-/****************************** FIND_MAX *************************/
-
-int find_max(double *maxfound,dataptr dz)
-{
-	int exit_status;
-	float *buffer = dz->sampbuf[0];
-	display_virtual_time(0L,dz);
-	while(dz->samps_left != 0) {
-		if((exit_status = read_samps(buffer,dz))<0) {
-			sprintf(errstr,"Cannot read data from sndfile.\n");
-			return(PROGRAM_ERROR);
-		}
-		find_maxsamp(maxfound,dz);
-		display_virtual_time(dz->total_samps_read,dz);
-    }
-	/*RWD NB this is a weird step, specifically for this program - balances to
-	 * MAXSAMP if sfile is actually higher than that.
-	 * must delete next line for a generic version!
-	 */
-	*maxfound = min(*maxfound,(double)F_MAXSAMP); /* e.g. found -32768: substitute 32767 */
-	return(FINISHED);
-}
-
-/**************************** MAXSAMP ***************************/
-
-void find_maxsamp(double *maxfound,dataptr dz)
-{   register long i;
-    double k;				 
-	float *buffer = dz->sampbuf[0];
-    for(i = 0; i < dz->ssampsread; i++) {
-	if((k = fabs(buffer[i])) > *maxfound)
-	    *maxfound = k;
-    }
-	return;
-}
-
-/**************************** GET_NORMALISATION_GAIN ***************************/
-
-int get_normalisation_gain(dataptr dz)
-{
-	int exit_status;
-	double maxfound = 0.0;
-	double loud_level = dz->param[LOUD_LEVEL] * (double)F_MAXSAMP;
-	
-	print_outmessage_flush("Finding maximum amplitude.\n");
-    if((exit_status = find_max(&maxfound,dz))<0)
-		return(exit_status);
-    if(flteq(maxfound,loud_level)) {
-		sprintf(errstr,"File is already at the specified level.\n");
-		return(GOAL_FAILED);
-    }
-    if((maxfound > loud_level) && dz->mode == LOUDNESS_NORM) {
-		sprintf(errstr,"File is already above the specified level.\n");
-		return(GOAL_FAILED);
-    }
-
-    dz->param[LOUD_GAIN]  = loud_level/maxfound;
-
-	display_virtual_time(0L,dz);
-	sprintf(errstr,"Normalising with Gain Factor = %lf\n", dz->param[LOUD_GAIN]);
-	print_outmessage_flush(errstr);
-	if(sndseekEx(dz->ifd[0],0L,0)<0) {
-		sprintf(errstr,"sndseek() failed.\n");
-		return(SYSTEM_ERROR);
-    }
-	reset_filedata_counters(dz);
-	return(CONTINUE);
-}
-
-/***************************** DO_BALANCE ************************/
-
-int do_balance(dataptr dz)
-{
-	int exit_status;
-	long maxloc1, maxloc;
-	long maxrep1, maxrep;
-	double max1, max2;
-	double mratio;
-	display_virtual_time(0,dz);
-	print_outmessage_flush("Getting max level from file 1.\n");
-	if((exit_status = find_maximum(dz->ifd[0],&maxloc,&maxrep,&max1,dz))<0)
-		return(exit_status);
-	if(max1 <= 0) {
-		sprintf(errstr,"First file has zero amplitude: can't proceed.\n");
-		return(GOAL_FAILED);
-	}
-	maxloc1 = maxloc;
-	maxrep1 = maxrep;
-	reset_filedata_counters(dz);
-	dz->samps_left = dz->insams[1];
-	display_virtual_time(0,dz);
-	print_outmessage_flush("Getting max level from file 2.\n");
-	if((exit_status = find_maximum(dz->ifd[1],&maxloc,&maxrep,&max2,dz))<0)
-		return(exit_status);
-	mratio = max2/max1;
-	if(sndseekEx(dz->ifd[0],0,0)<0) {
-		sprintf(errstr,"sndseek failed.\n");
-		return(SYSTEM_ERROR);
-	}
-	reset_filedata_counters(dz);
-	display_virtual_time(0,dz);
-	sprintf(errstr,"Adjusting gain of 1st infile by %lf\n",mratio);
-	print_outmessage_flush(errstr);
-	if((exit_status = balance(mratio,dz))< 0)	
-		return(exit_status);
-//TW No longer required: takes place in PEAK procedure
-//	if((exit_status = write_maxsamp_properties(max2,maxloc1,maxrep1,dz))<0)
-//		return(exit_status);
-	return(FINISHED);
-}
-
-/***************************** BALANCE ************************/
-
-int balance(double mratio,dataptr dz)
-{
-	int exit_status;
-	long /*samps_read,*/ ssampsread, n;
-	/*double maxsamp = 0;*/
-	float *buffer = dz->sampbuf[0];
-	while((ssampsread = fgetfbufEx(buffer, dz->buflen,dz->ifd[0],0)) > 0) {		
-		for(n=0;n<ssampsread;n++)
-			buffer[n] = (float) /*round*/((double)buffer[n] * mratio);
-		if((exit_status = write_exact_samps(buffer,ssampsread,dz))<0)
-			return(exit_status);
-	}
-	if(ssampsread<0) {
-		sprintf(errstr,"Sound read error.\n");
-		return(SYSTEM_ERROR);
-	}
-	return(FINISHED);
-}
-
-/***************************** FIND_MAXIMUM ************************/
-
-int find_maximum(int infile,long *maxloc,long *maxrep,double *maxsamp,dataptr dz)
-{
-	long  ssampsread, last_total_ssampsread = 0, total_samps_read = 0;
-	float *buffer = dz->sampbuf[0];
-	*maxsamp = 0;
-	while((ssampsread = fgetfbufEx(buffer, dz->buflen,infile,0)) > 0) {
-		total_samps_read += ssampsread;		
-		get_max(maxsamp,ssampsread,last_total_ssampsread,maxloc,maxrep,dz);
-		last_total_ssampsread += ssampsread;
-		display_virtual_time(total_samps_read,dz);
-	}
-	if(ssampsread<0) {
-		sprintf(errstr,"Sound read error.\n");
-		return(SYSTEM_ERROR);
-	}
-	return(FINISHED);
-}
-
-/***************************** GET_MAX ************************/
-
-void get_max(double *maxsamp,long ssampsread,long last_total_ssampsread, long *maxloc, long *maxrep,dataptr dz)
-{
-	register long n;
-	float thisamp;
-	float *buffer = dz->sampbuf[0];
-	for(n=0;n<ssampsread;n++) {
-		if((thisamp = (float)fabs(buffer[n])) > *maxsamp) {
-			*maxsamp = thisamp;
-			*maxloc  = last_total_ssampsread + n;
-			*maxrep = 1;
-		} else if(flteq(thisamp,*maxsamp)) {
-			(*maxrep)++;
-		}
-	}
-	return;
-}
-
-/********************** WRITE_MAXSAMP_PROPERTIES ***************************/
-//
-//int write_maxsamp_properties(double max1,long maxloc,long maxrep,dataptr dz)
-//{
-//
-//	float maxpfamp = (float)max1;
-//
-//	if(maxloc<0 || maxrep<0) {
-//		sprintf(errstr,"Failed to establish location and/or repetition-count of max-sample\n");
-//		return(GOAL_FAILED);
-//	}
-	/* TODO: scrap all this for the PEAK chunk instead! */
-//* don't store in 'maxamp' as this is (long) in old files: 
-//	if(sndputprop(dz->ofd, "maxpfamp", (char *)&maxpfamp, sizeof(float)) < 0) {
-//		sprintf(errstr,"Can't write new max-sample to sndfile.\n");
-//		return(PROGRAM_ERROR);
-//	}
-//	if(sndputprop(dz->ofd, "maxloc", (char *)&maxloc, sizeof(long)) < 0) {
-//		sprintf(errstr,"Can't write location of max-sample to sndfile.\n");
-//		return(PROGRAM_ERROR);
-//	}
-//	if(sndputprop(dz->ofd, "maxrep", (char *)&maxrep, sizeof(long)) < 0) {
-//		sprintf(errstr,"Can't write repeat-count of max-sample to sndfile.\n");
-//		return(PROGRAM_ERROR);
-//	}
-//	return(FINISHED);
-//}
-
-/********************** DO_MULTIFILE_LOUDNESS ***************************/
-
-int do_multifile_loudness(dataptr dz)
-{
-	int exit_status;
-	double *greater, greatest = 0.0, maxfound;
-	/*RWD*/
-	double dbamp;
-	int clipsamps = 1;
-	double peak_val = 0.0;
-
-	int orig_ifd = dz->ifd[0];
- //TW REVISED Dec 2002
-//	int n, do_gain, namelen, maxno = 0;
-	int n, do_gain, maxno = 0;
-//TW REVISED Dec 2002
-//	char outfilename[256], *outfilenumber;	   /* RWD fname was only [64] */
-	char outfilename[256];
-	long numclipped = 0;
-	double this_gain = 1.0, maxnoclip = 1.0;
-
-	if((greater = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
-		sprintf(errstr,"Insufficient memory to store file maxima\n");
-		return(MEMORY_ERROR);
-	}
-
-	if(dz->true_outfile_stype == SAMP_FLOAT)
-		if(dz->clip_floatsams == 0)
-			clipsamps = 0;
-
-	fprintf(stdout,"INFO: Finding loudest file\n");
-	fflush(stdout);
-	for(n=0;n<dz->infilecnt;n++) {
-		maxfound = 0.0;
-		dz->ifd[0] = dz->ifd[n];
-		dz->total_samps_written = 0;
-		dz->samps_left = dz->insams[n];
-		dz->total_samps_read = 0;		
-	    if((exit_status = find_max(&maxfound,dz))<0) {
-			dz->ifd[0] = orig_ifd;
-			return(exit_status);
-		}
-		if(maxfound > greatest) {
-			greatest = maxfound;
-			maxno = n;
-		}
-		greater[n] = maxfound/F_MAXSAMP;
-	}
-	greatest /= F_MAXSAMP;
-	dz->ifd[0] = orig_ifd;
-	dbamp = 20 * log10(greatest);  /*RWD*/
-	if(dz->mode==LOUDNESS_LOUDEST) {
-		fprintf(stdout,"INFO: loudest file is %s with level %lf (%.3f dB)\n",dz->wordstor[maxno],greatest,dbamp);
-		fflush(stdout);
-		return(FINISHED);
-	}
-	fprintf(stdout,"INFO: Equalising levels\n");
-	fflush(stdout);
-	for(n=0;n<dz->infilecnt;n++) {
-		dz->ssampsread = 0;
-		dz->total_samps_read = 0;
-		dz->ifd[0] = dz->ifd[n];
-		if(sndseekEx(dz->ifd[0],0L,0)<0) {
-			sprintf(errstr,"sndseekEx() failed.\n");
-			return(SYSTEM_ERROR);
-	    }
-		dz->total_samps_written = 0;
-		dz->samps_left = dz->insams[n];
-		dz->total_samps_read = 0;		
-		if(!flteq(greatest,greater[n])) {
-			this_gain = greatest/greater[n];
-			maxnoclip  = fabs((double)F_MAXSAMP/this_gain);
-			do_gain = 1;
-		} else {
-			do_gain = 0;
-		}
-		if(n>0) {
-			strcpy(outfilename,dz->wordstor[dz->infilecnt]);
-			/* RWD 9:2001 the -1 is unsafe if outname is only one char! */
-//TW This is a sloom requirement,as standard sloom temp outfile name is 'cdptest0'
-// and temporary-file housekeeping requires files to be named cdptestN in numeric order of N
-// However, we can do it differently for cmdline case....
-			if(sloom)
-				insert_new_number_at_filename_end(outfilename,n,1);
-			else
-				insert_new_number_at_filename_end(outfilename,n,0);
-			if((exit_status = create_sized_outfile(outfilename,dz))<0) {
-				sprintf(errstr,"Cannot open output file %s\n", outfilename);
-				dz->ifd[0] = orig_ifd;
-				return(DATA_ERROR);
-			}
-		}
-		while(dz->samps_left > 0) {
-			if((exit_status = read_samps(dz->sampbuf[0],dz))<0) {
-				sprintf(errstr,"Cannot read data from sndfile %d\n",n+1);
-				dz->ifd[0] = orig_ifd;
-				return(PROGRAM_ERROR);
-			}
-			if(do_gain)
-				gain(dz->ssampsread,this_gain,maxnoclip,&numclipped,clipsamps,&peak_val,dz);
-			if(dz->ssampsread > 0) {
-				if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0) {
-					dz->ifd[0] = orig_ifd;
-					return(exit_status);
-				}
-			}
-		}
-		if(n < dz->infilecnt - 1) {
-			if((exit_status = headwrite(dz->ofd,dz))<0) {
-				dz->ifd[0] = orig_ifd;
-				return(exit_status);
-			}
-			if((exit_status = reset_peak_finder(dz))<0)
-				return(exit_status);
-			if(sndcloseEx(dz->ofd) < 0) {
-				fprintf(stdout,"WARNING: Can't close output soundfile %s\n",outfilename);
-				fflush(stdout);
-			}
-			dz->ofd = -1;
-		}
-	}
-	dz->ifd[0] = orig_ifd;
-	/*RWD*/
-	if(clipsamps && (numclipped > 0))
-		sprintf(errstr, "WARNING: %ld samples were clipped.\n", numclipped);
-	dz->peak_fval = peak_val;
-	/*will get written to header automatically*/
-	return(FINISHED);
-}
-
-
-//TW NEW FUNCTION, updated for floatsams and new-style clipping detection
-/********************** GAINENV ***************************/
-
-int gainenv(long samples,long *last_total,double maxnoclip,long *numclipped,int do_clip,double *peak,dataptr dz)
-{
-	int exit_status;
-	register long i;            
-	double s, buf_peak = *peak;
-	double timeincr = 1.0/(double)dz->infile->srate;
-	float *buffer = dz->sampbuf[0];
-	double time = (double)(*last_total/dz->infile->channels)/(double)dz->infile->srate;
-
-	for(i = 0; i < samples; i++) {
-		if(i % dz->infile->channels == 0) {
-			if((exit_status = read_value_from_brktable(time,LOUD_GAIN,dz))<0)
-				return(exit_status);
-			time += timeincr;
-		}
-		s = buffer[i];
-		s *= dz->param[LOUD_GAIN];
-		if(s >= 0) {
-			if(do_clip && (s > maxnoclip)) {
-				(*numclipped)++;
-				s = 1.0;
-			}
-			buf_peak = max(buf_peak,s);
-		} else {
-			if(do_clip && (s < -maxnoclip)) {
-				(*numclipped)++;
-				s = -1.0;
-			}
-			buf_peak = max(buf_peak,-s);
-		}
-		buffer[i] = (float)s;
-	}
-	*peak = buf_peak;
-	*last_total = dz->total_samps_read;
-	return(FINISHED);
-}
-
+/*
+ * Copyright (c) 1983-2023 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * 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
+ *
+ */
+
+
+
+/* floatsam version*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <cdpmain.h>
+#include <modify.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <modify.h>
+
+#include <sfsys.h>
+
+/* RWD added do_clip, peak (later, sort out nChans PEAK stuff... */
+static void gain(int samples,double multiplier,double maxnoclip,long *numclipped,
+                 int do_clip,double *peak,dataptr dz);
+static int find_max(double *maxfound,dataptr dz);
+static int  find_maximum(int infile,int *maxloc,int *maxrep,double *maxsamp,dataptr dz);
+static void     get_max(double *,int,int,int *,int *,dataptr dz);
+static int  balance(double mratio,dataptr dz);
+//TW replaced by peakchunk
+//static int    write_maxsamp_properties(double,long,long,dataptr dz);
+static int  do_balance(dataptr dz);
+static int  gain_process(dataptr dz);
+static int  get_normalisation_gain(dataptr dz);
+static void do_normalise(dataptr dz);
+static void do_phase_invert(dataptr dz);
+static void find_maxsamp(double *maxfound,dataptr dz);
+static int  do_multifile_loudness(dataptr dz);
+
+
+#define MAX_DBGAIN       (90)
+
+//TW UPDATE: further updated for floatsams and new-style clipping detection
+int gainenv(int samples,int *last_total,double maxnoclip,int *numclipped,int do_clip,double *peak,dataptr dz);
+
+/************************** LOUDNESS_PROCESS *******************************/
+
+int loudness_process(dataptr dz)
+{
+    int n, m;
+    double maxtime,intime, ratio;  /*RWD April 2004 needed to add these  */
+    switch(dz->mode) {
+    case(LOUD_PROPOR):
+    case(LOUD_DB_PROPOR):
+        maxtime = dz->brk[LOUD_GAIN][(dz->brksize[LOUD_GAIN] - 1) * 2];
+        intime = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
+        ratio = intime/maxtime;
+        for(n=0,m = 0;n < dz->brksize[LOUD_GAIN];n++,m+=2)
+            dz->brk[LOUD_GAIN][m] = dz->brk[LOUD_GAIN][m] * ratio;
+        dz->mode = LOUDNESS_GAIN;
+        break;
+    case(LOUDNESS_DBGAIN):
+        if(dz->brksize[LOUD_GAIN]) {
+            for(n=0,m=1;n < dz->brksize[LOUD_GAIN];n++,m+=2)
+                dz->brk[LOUD_GAIN][m] = dbtogain(dz->brk[LOUD_GAIN][m]);
+        } else {
+            dz->param[LOUD_GAIN] = dbtogain(dz->param[LOUD_GAIN]);
+        }
+        break;
+    }
+    switch(dz->mode) {
+    case(LOUDNESS_LOUDEST):
+    case(LOUDNESS_EQUALISE):    return do_multifile_loudness(dz);
+    case(LOUDNESS_BALANCE):     return do_balance(dz);
+    default:                                    return gain_process(dz);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/************************** GAIN_PROCESS *******************************/
+
+int gain_process(dataptr dz)
+{
+    int exit_status;
+    double maxnoclip = F_MAXSAMP, peakval = 0.0;
+    //TW UPDATE
+    int numclipped = 0, last_total = 0;
+    int clipsamps = 1;
+    float *buffer = dz->sampbuf[0];
+
+    if(dz->true_outfile_stype == SAMP_FLOAT)
+        if(dz->clip_floatsams == 0)
+            clipsamps = 0;
+
+    switch(dz->mode) {
+    case(LOUDNESS_NORM):
+    case(LOUDNESS_SET):
+        if((exit_status = get_normalisation_gain(dz))!=CONTINUE)
+            return(exit_status);
+        break;
+    }
+    display_virtual_time(0,dz);
+    while(dz->samps_left > 0) {
+        if((exit_status = read_samps(buffer,dz))<0) {
+            sprintf(errstr,"Cannot read data from sndfile.\n");
+            return(PROGRAM_ERROR);
+        }
+        switch(dz->mode) {
+        case(LOUDNESS_GAIN):
+        case(LOUDNESS_DBGAIN):
+            //TW UPDATE >>
+            if(dz->brksize[LOUD_GAIN])
+                gainenv(dz->ssampsread,&last_total,maxnoclip,&numclipped,clipsamps,&peakval,dz);
+            else if(dz->param[LOUD_GAIN] <= FLTERR) {
+                sprintf(errstr,"With gain of %lf the soundfile will be reduced to SILENCE!\n",dz->param[LOUD_GAIN]);
+                return(DATA_ERROR);
+            } else
+                //<< TW UPDATE
+                gain(dz->ssampsread,dz->param[LOUD_GAIN],maxnoclip,&numclipped,clipsamps,&peakval,dz);
+            break;
+        case(LOUDNESS_NORM):
+        case(LOUDNESS_SET):
+            do_normalise(dz);
+            break;
+        case(LOUDNESS_PHASE):
+            do_phase_invert(dz);
+            break;
+        }
+        if(dz->ssampsread > 0) {
+            if((exit_status = write_exact_samps(buffer,dz->ssampsread,dz))<0)
+                return(exit_status);
+        }
+    }
+    if(clipsamps && (numclipped > 0))
+        sprintf(errstr, "WARNING: %ld samples were clipped.\n", numclipped);
+    dz->peak_fval = peakval;
+    /*will get written to header automatically*/
+    return(FINISHED);
+}
+
+/************************** GAIN *******************************/
+
+void gain(long samples,double multiplier,double maxnoclip,long *numclipped,
+          int do_clip,double *peak,dataptr dz)
+{
+    int i;
+    double s, buf_peak = *peak;
+    float *buffer = dz->sampbuf[0];
+    if(multiplier < 0.0)
+        multiplier = -multiplier;
+    for(i = 0; i < samples; i++) {
+        s = buffer[i] * multiplier;
+        if(s >= 0) {
+            if(do_clip && (s > maxnoclip)) {
+                (*numclipped)++;
+                s = F_MAXSAMP;
+            }
+            buf_peak = max(buf_peak,s);
+        } else {
+            if(do_clip && (-s > maxnoclip)) {
+                (*numclipped)++;
+                s = -F_MAXSAMP;
+            }
+            buf_peak = max(buf_peak,-s);
+        }
+        buffer[i] = (float) s;
+        *peak = buf_peak;
+    }
+
+}
+
+/**************************** DO_NORMALISE ***************************/
+/* RWD NB my old floatsam version added a peak_val arg */
+void do_normalise(dataptr dz)
+{
+    register int i;
+
+    float *buffer = dz->sampbuf[0];
+    float dgain = (float) dz->param[LOUD_GAIN];
+    for(i = 0; i < dz->ssampsread; i++) {
+        //TW    float sampl;
+        //TW    sampl  = buffer[i] * dgain;
+        //TW    buffer[i] =  sampl;
+        //TW must cast to float anyway, as multiply gives double
+        buffer[i] =  (float)(buffer[i] * dgain);
+    }
+}
+
+/**************************** DO_PHASE_INVERT ***************************/
+
+void do_phase_invert(dataptr dz)
+{   register int i;
+    double samplong;
+    float *buffer = dz->sampbuf[0];
+    for(i = 0; i < dz->ssampsread; i++) {
+        samplong  = -buffer[i];
+        samplong = min(samplong,(double)F_MAXSAMP);
+        buffer[i] = (float)(samplong);
+    }
+}
+
+/****************************** FIND_MAX *************************/
+
+int find_max(double *maxfound,dataptr dz)
+{
+    int exit_status;
+    float *buffer = dz->sampbuf[0];
+    display_virtual_time(0L,dz);
+    while(dz->samps_left != 0) {
+        if((exit_status = read_samps(buffer,dz))<0) {
+            sprintf(errstr,"Cannot read data from sndfile.\n");
+            return(PROGRAM_ERROR);
+        }
+        find_maxsamp(maxfound,dz);
+        display_virtual_time(dz->total_samps_read,dz);
+    }
+    /*RWD NB this is a weird step, specifically for this program - balances to
+     * MAXSAMP if sfile is actually higher than that.
+     * must delete next line for a generic version!
+     */
+    *maxfound = min(*maxfound,(double)F_MAXSAMP); /* e.g. found -32768: substitute 32767 */
+    return(FINISHED);
+}
+
+/**************************** MAXSAMP ***************************/
+
+void find_maxsamp(double *maxfound,dataptr dz)
+{   register long i;
+    double k;
+    float *buffer = dz->sampbuf[0];
+    for(i = 0; i < dz->ssampsread; i++) {
+        if((k = fabs(buffer[i])) > *maxfound)
+            *maxfound = k;
+    }
+    return;
+}
+
+/**************************** GET_NORMALISATION_GAIN ***************************/
+
+int get_normalisation_gain(dataptr dz)
+{
+    int exit_status;
+    double maxfound = 0.0;
+    double loud_level = dz->param[LOUD_LEVEL] * (double)F_MAXSAMP;
+
+    print_outmessage_flush("Finding maximum amplitude.\n");
+    if((exit_status = find_max(&maxfound,dz))<0)
+        return(exit_status);
+    if(flteq(maxfound,loud_level)) {
+        sprintf(errstr,"File is already at the specified level.\n");
+        return(GOAL_FAILED);
+    }
+    if((maxfound > loud_level) && dz->mode == LOUDNESS_NORM) {
+        sprintf(errstr,"File is already above the specified level.\n");
+        return(GOAL_FAILED);
+    }
+
+    dz->param[LOUD_GAIN]  = loud_level/maxfound;
+
+    display_virtual_time(0L,dz);
+    sprintf(errstr,"Normalising with Gain Factor = %lf\n", dz->param[LOUD_GAIN]);
+    print_outmessage_flush(errstr);
+    if(sndseekEx(dz->ifd[0],0L,0)<0) {
+        sprintf(errstr,"sndseek() failed.\n");
+        return(SYSTEM_ERROR);
+    }
+    reset_filedata_counters(dz);
+    return(CONTINUE);
+}
+
+/***************************** DO_BALANCE ************************/
+
+int do_balance(dataptr dz)
+{
+    int exit_status;
+    int maxloc;
+    int maxrep;
+    double max1, max2;
+    double mratio;
+    display_virtual_time(0,dz);
+    print_outmessage_flush("Getting max level from file 1.\n");
+    if((exit_status = find_maximum(dz->ifd[0],&maxloc,&maxrep,&max1,dz))<0)
+        return(exit_status);
+    if(max1 <= 0) {
+        sprintf(errstr,"First file has zero amplitude: can't proceed.\n");
+        return(GOAL_FAILED);
+    }
+    //maxloc1 = maxloc;
+    //maxrep1 = maxrep;
+    reset_filedata_counters(dz);
+    dz->samps_left = dz->insams[1];
+    display_virtual_time(0,dz);
+    print_outmessage_flush("Getting max level from file 2.\n");
+    if((exit_status = find_maximum(dz->ifd[1],&maxloc,&maxrep,&max2,dz))<0)
+        return(exit_status);
+    mratio = max2/max1;
+    if(sndseekEx(dz->ifd[0],0,0)<0) {
+        sprintf(errstr,"sndseek failed.\n");
+        return(SYSTEM_ERROR);
+    }
+    reset_filedata_counters(dz);
+    display_virtual_time(0,dz);
+    sprintf(errstr,"Adjusting gain of 1st infile by %lf\n",mratio);
+    print_outmessage_flush(errstr);
+    if((exit_status = balance(mratio,dz))< 0)
+        return(exit_status);
+    //TW No longer required: takes place in PEAK procedure
+    //  if((exit_status = write_maxsamp_properties(max2,maxloc1,maxrep1,dz))<0)
+    //          return(exit_status);
+    return(FINISHED);
+}
+
+/***************************** BALANCE ************************/
+
+int balance(double mratio,dataptr dz)
+{
+    int exit_status;
+    int /*samps_read,*/ ssampsread, n;
+    /*double maxsamp = 0;*/
+    float *buffer = dz->sampbuf[0];
+    while((ssampsread = fgetfbufEx(buffer, dz->buflen,dz->ifd[0],0)) > 0) {
+        for(n=0;n<ssampsread;n++)
+            buffer[n] = (float) /*round*/((double)buffer[n] * mratio);
+        if((exit_status = write_exact_samps(buffer,ssampsread,dz))<0)
+            return(exit_status);
+    }
+    if(ssampsread<0) {
+        sprintf(errstr,"Sound read error.\n");
+        return(SYSTEM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** FIND_MAXIMUM ************************/
+
+int find_maximum(int infile,long *maxloc,long *maxrep,double *maxsamp,dataptr dz)
+{
+    int  ssampsread, last_total_ssampsread = 0, total_samps_read = 0;
+    float *buffer = dz->sampbuf[0];
+    *maxsamp = 0;
+    while((ssampsread = fgetfbufEx(buffer, dz->buflen,infile,0)) > 0) {
+        total_samps_read += ssampsread;
+        get_max(maxsamp,ssampsread,last_total_ssampsread,maxloc,maxrep,dz);
+        last_total_ssampsread += ssampsread;
+        display_virtual_time(total_samps_read,dz);
+    }
+    if(ssampsread<0) {
+        sprintf(errstr,"Sound read error.\n");
+        return(SYSTEM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** GET_MAX ************************/
+
+void get_max(double *maxsamp,long ssampsread,long last_total_ssampsread, long *maxloc, long *maxrep,dataptr dz)
+{
+    register int n;
+    float thisamp;
+    float *buffer = dz->sampbuf[0];
+    for(n=0;n<ssampsread;n++) {
+        if((thisamp = (float)fabs(buffer[n])) > *maxsamp) {
+            *maxsamp = thisamp;
+            *maxloc  = last_total_ssampsread + n;
+            *maxrep = 1;
+        } else if(flteq(thisamp,*maxsamp)) {
+            (*maxrep)++;
+        }
+    }
+    return;
+}
+
+/********************** WRITE_MAXSAMP_PROPERTIES ***************************/
+//
+//int write_maxsamp_properties(double max1,long maxloc,long maxrep,dataptr dz)
+//{
+//
+//      float maxpfamp = (float)max1;
+//
+//      if(maxloc<0 || maxrep<0) {
+//              sprintf(errstr,"Failed to establish location and/or repetition-count of max-sample\n");
+//              return(GOAL_FAILED);
+//      }
+/* TODO: scrap all this for the PEAK chunk instead! */
+//* don't store in 'maxamp' as this is (long) in old files:
+//      if(sndputprop(dz->ofd, "maxpfamp", (char *)&maxpfamp, sizeof(float)) < 0) {
+//              sprintf(errstr,"Can't write new max-sample to sndfile.\n");
+//              return(PROGRAM_ERROR);
+//      }
+//      if(sndputprop(dz->ofd, "maxloc", (char *)&maxloc, sizeof(long)) < 0) {
+//              sprintf(errstr,"Can't write location of max-sample to sndfile.\n");
+//              return(PROGRAM_ERROR);
+//      }
+//      if(sndputprop(dz->ofd, "maxrep", (char *)&maxrep, sizeof(long)) < 0) {
+//              sprintf(errstr,"Can't write repeat-count of max-sample to sndfile.\n");
+//              return(PROGRAM_ERROR);
+//      }
+//      return(FINISHED);
+//}
+
+/********************** DO_MULTIFILE_LOUDNESS ***************************/
+
+int do_multifile_loudness(dataptr dz)
+{
+    int exit_status;
+    double *greater, greatest = 0.0, maxfound;
+    /*RWD*/
+    double dbamp;
+    int clipsamps = 1;
+    double peak_val = 0.0;
+
+    int orig_ifd = dz->ifd[0];
+    //TW REVISED Dec 2002
+    //  int n, do_gain, namelen, maxno = 0;
+    int n, do_gain, maxno = 0;
+    //TW REVISED Dec 2002
+    //  char outfilename[256], *outfilenumber;     /* RWD fname was only [64] */
+    char outfilename[256];
+    int numclipped = 0;
+    double this_gain = 1.0, maxnoclip = 1.0;
+
+    if((greater = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"Insufficient memory to store file maxima\n");
+        return(MEMORY_ERROR);
+    }
+
+    if(dz->true_outfile_stype == SAMP_FLOAT)
+        if(dz->clip_floatsams == 0)
+            clipsamps = 0;
+
+    fprintf(stdout,"INFO: Finding loudest file\n");
+    fflush(stdout);
+    for(n=0;n<dz->infilecnt;n++) {
+        maxfound = 0.0;
+        dz->ifd[0] = dz->ifd[n];
+        dz->total_samps_written = 0;
+        dz->samps_left = dz->insams[n];
+        dz->total_samps_read = 0;
+        if((exit_status = find_max(&maxfound,dz))<0) {
+            dz->ifd[0] = orig_ifd;
+            return(exit_status);
+        }
+        if(maxfound > greatest) {
+            greatest = maxfound;
+            maxno = n;
+        }
+        greater[n] = maxfound/F_MAXSAMP;
+    }
+    greatest /= F_MAXSAMP;
+    dz->ifd[0] = orig_ifd;
+    dbamp = 20 * log10(greatest);  /*RWD*/
+    if(dz->mode==LOUDNESS_LOUDEST) {
+        fprintf(stdout,"INFO: loudest file is %s with level %lf (%.3f dB)\n",dz->wordstor[maxno],greatest,dbamp);
+        fflush(stdout);
+        return(FINISHED);
+    }
+    fprintf(stdout,"INFO: Equalising levels\n");
+    fflush(stdout);
+    for(n=0;n<dz->infilecnt;n++) {
+        dz->ssampsread = 0;
+        dz->total_samps_read = 0;
+        dz->ifd[0] = dz->ifd[n];
+        if(sndseekEx(dz->ifd[0],0L,0)<0) {
+            sprintf(errstr,"sndseekEx() failed.\n");
+            return(SYSTEM_ERROR);
+        }
+        dz->total_samps_written = 0;
+        dz->samps_left = dz->insams[n];
+        dz->total_samps_read = 0;
+        if(!flteq(greatest,greater[n])) {
+            this_gain = greatest/greater[n];
+            maxnoclip  = fabs((double)F_MAXSAMP/this_gain);
+            do_gain = 1;
+        } else {
+            do_gain = 0;
+        }
+        if(n>0) {
+            strcpy(outfilename,dz->wordstor[dz->infilecnt]);
+            /* RWD 9:2001 the -1 is unsafe if outname is only one char! */
+            //TW This is a sloom requirement,as standard sloom temp outfile name is 'cdptest0'
+            // and temporary-file housekeeping requires files to be named cdptestN in numeric order of N
+            // However, we can do it differently for cmdline case....
+            if(sloom)
+                insert_new_number_at_filename_end(outfilename,n,1);
+            else
+                insert_new_number_at_filename_end(outfilename,n,0);
+            if((exit_status = create_sized_outfile(outfilename,dz))<0) {
+                sprintf(errstr,"Cannot open output file %s\n", outfilename);
+                dz->ifd[0] = orig_ifd;
+                return(DATA_ERROR);
+            }
+        }
+        while(dz->samps_left > 0) {
+            if((exit_status = read_samps(dz->sampbuf[0],dz))<0) {
+                sprintf(errstr,"Cannot read data from sndfile %d\n",n+1);
+                dz->ifd[0] = orig_ifd;
+                return(PROGRAM_ERROR);
+            }
+            if(do_gain)
+                gain(dz->ssampsread,this_gain,maxnoclip,&numclipped,clipsamps,&peak_val,dz);
+            if(dz->ssampsread > 0) {
+                if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0) {
+                    dz->ifd[0] = orig_ifd;
+                    return(exit_status);
+                }
+            }
+        }
+        if(n < dz->infilecnt - 1) {
+            if((exit_status = headwrite(dz->ofd,dz))<0) {
+                dz->ifd[0] = orig_ifd;
+                return(exit_status);
+            }
+            if((exit_status = reset_peak_finder(dz))<0)
+                return(exit_status);
+            if(sndcloseEx(dz->ofd) < 0) {
+                fprintf(stdout,"WARNING: Can't close output soundfile %s\n",outfilename);
+                fflush(stdout);
+            }
+            dz->ofd = -1;
+        }
+    }
+    dz->ifd[0] = orig_ifd;
+    /*RWD*/
+    if(clipsamps && (numclipped > 0))
+        sprintf(errstr, "WARNING: %ld samples were clipped.\n", numclipped);
+    dz->peak_fval = peak_val;
+    /*will get written to header automatically*/
+    return(FINISHED);
+}
+
+
+//TW NEW FUNCTION, updated for floatsams and new-style clipping detection
+/********************** GAINENV ***************************/
+
+int gainenv(int samples,int *last_total,double maxnoclip,long *numclipped,int do_clip,double *peak,dataptr dz)
+{
+    int exit_status;
+    register int i;
+    double s, buf_peak = *peak;
+    double timeincr = 1.0/(double)dz->infile->srate;
+    float *buffer = dz->sampbuf[0];
+    double time = (double)(*last_total/dz->infile->channels)/(double)dz->infile->srate;
+
+    for(i = 0; i < samples; i++) {
+        if(i % dz->infile->channels == 0) {
+            if((exit_status = read_value_from_brktable(time,LOUD_GAIN,dz))<0)
+                return(exit_status);
+            time += timeincr;
+        }
+        s = buffer[i];
+        s *= dz->param[LOUD_GAIN];
+        if(s >= 0) {
+            if(do_clip && (s > maxnoclip)) {
+                (*numclipped)++;
+                s = 1.0;
+            }
+            buf_peak = max(buf_peak,s);
+        } else {
+            if(do_clip && (s < -maxnoclip)) {
+                (*numclipped)++;
+                s = -1.0;
+            }
+            buf_peak = max(buf_peak,-s);
+        }
+        buffer[i] = (float)s;
+    }
+    *peak = buf_peak;
+    *last_total = dz->total_samps_read;
+    return(FINISHED);
+}