/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef unix #define round(x) lround((x)) #endif static int do_mix2(float *inbuf1,float *inbuf2,double *dblbuf,float *obuf,dataptr dz); static int do_mix2_stagger(float *inbuf1,float *obuf,dataptr dz); static int do_mix2_skip(dataptr dz); static int cross_stagger(int *total_samps_read,int *end_of_samps_to_process,float *obuf,dataptr dz); static int pre_crossmix(int *samps_read2,int *cross_end,int *total_samps_read, int *end_of_samps_to_process,float *inbuf1,float *inbuf2,float *obuf,dataptr dz); static int crossmix(int *samps_read2,int *cross_end,int *total_samps_read,int *end_of_samps_to_process, float *inbuf1,float *inbuf2,float *obuf,dataptr dz); static int cross(int startcross,int endcross,float *inbuf1,float *inbuf2,float *obuf,dataptr dz); static double read_cos(double d,dataptr dz); static int advance_in_files(int *samps_read2,int *total_samps_read,int *end_of_samps_to_process, int *cross_end,float *inbuf1,float *inbuf2,dataptr dz); static void copy_to_channel(float *inbuf,float *obuf,int sampcnt,int outchans); static int renew_bufs(int typ,float *buf0,float *buf1,dataptr dz); static int do_stitch(int typ,int *mbf,int *sbf,float *buf0,float *buf1,double atten,int bflen,dataptr dz); static int flush_bufs(int typ,int *mbf,int *sbf,float *buf0,float *buf1,dataptr dz); //TW JAN 2010: FOR MULTICHANNEL //static int read_automix_sound(int *activebuf,int *chans,int chantype,dataptr dz); static int read_automix_sound(int *activebuf,dataptr dz); /************************************ MIXTWO ************************************/ int mixtwo(dataptr dz) { int exit_status; char tempfnam[200]; double *dblbuf = (double *) dz->sampbuf[3]; /* RWD I suppose we can keep this...*/ float *inbuf1 = dz->sampbuf[0]; float *inbuf2 = dz->sampbuf[1]; float *obuf = dz->sampbuf[2]; int extra_skip; if(dz->iparam[MIX_STTA] > 0) { if((sndseekEx(dz->ifd[0],dz->iparam[MIX_STTA],0))<0) { sprintf(errstr,"sndseek() failed in first file.\n"); return(SYSTEM_ERROR); } } if((extra_skip = dz->iparam[MIX_STTA] - dz->iparam[MIX_STAGGER]) > 0) { if((dz->iparam[MIX_SKIP] += extra_skip) > dz->insams[1]) { sprintf(errstr,"Mix skips the 2nd file entirely.\n"); return(DATA_ERROR); } } if(dz->iparam[MIX_SKIP] > 0) { if((exit_status = do_mix2_skip(dz))<0) return(exit_status); } if((dz->iparam[MIX_STAGGER] -= dz->iparam[MIX_STTA]) > 0) { if((exit_status = do_mix2_stagger(inbuf1,obuf,dz))<0) return(exit_status); } else { dz->iparam[MIX_STAGGER] = 0; } if((exit_status = do_mix2(inbuf1,inbuf2,dblbuf,obuf,dz))<0) return(exit_status); if(is_converted_to_stereo >= 0) { strcpy(tempfnam,snd_getfilename(dz->ifd[is_converted_to_stereo])); sndcloseEx(dz->ifd[is_converted_to_stereo]); if(remove(tempfnam)<0) fprintf(stdout, "ERROR: %s: Can't remove temporary stereo soundfile %s.\n",sferrstr(),tempfnam); dz->ifd[is_converted_to_stereo] = -1; } return(FINISHED); } /************************************ DO_MIX2_SKIP ************************************/ int do_mix2_skip(dataptr dz) { if((sndseekEx(dz->ifd[1],dz->iparam[MIX_SKIP],0))<0) { sprintf(errstr,"sndseek() failed: do_mix2_skip()\n"); return(SYSTEM_ERROR); } return(FINISHED); } /************************************ DO_MIX2_STAGGER ************************************/ int do_mix2_stagger(float *inbuf1,float *obuf,dataptr dz) { int exit_status; int stagbufs,stagsamps, n; //TW int shsecsize = F_SECSIZE; /* RWD I suppose we can keep this...*/ int samps_read; stagbufs = dz->iparam[MIX_STAGGER]/dz->buflen; stagsamps = dz->iparam[MIX_STAGGER] % dz->buflen; /*RWD do we still need this test? Is it still kosher ? */ if(((stagsamps/shsecsize)*shsecsize) != stagsamps) { sprintf(errstr,"Error in sector arithmetic: do_mix2_stagger()\n"); return(PROGRAM_ERROR); } while(stagbufs > 0) { if((samps_read = fgetfbufEx(inbuf1,dz->buflen,dz->ifd[0],0)) < dz->buflen) { if(samps_read < 0) { sprintf(errstr,"Sound read error.\n"); return(SYSTEM_ERROR); } else { sprintf(errstr,"Problem 1 reading from file1 during stagger\n"); return(PROGRAM_ERROR); } } for(n=0;nbuflen;n++) obuf[n] = (float)(inbuf1[n] * dz->param[MIX2_GAIN1]); if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); stagbufs--; } if(stagsamps) { if((samps_read = fgetfbufEx(inbuf1,stagsamps,dz->ifd[0],0)) < stagsamps) { if(samps_read < 0) { sprintf(errstr,"Sound read error.\n"); return(SYSTEM_ERROR); } else { sprintf(errstr,"Problem 2 reading from file1 during stagger\n"); return(PROGRAM_ERROR); } } for(n=0;nparam[MIX2_GAIN1]); if((exit_status = write_samps(obuf,stagsamps,dz))<0) return(exit_status); } return(FINISHED); } /************************************ DO_MIX2 ************************************/ int do_mix2(float *inbuf1,float *inbuf2,double *dblbuf,float *obuf,dataptr dz) { int exit_status; int gross_samps_read = 1, gross_total_samps_read = 0, cutoff_in_buf; int samps_read1, samps_read2, ssampsread, ssampsread1, ssampsread2, n; unsigned int cutoff_samps; cutoff_samps = (dz->iparam[MIX_DURA] - dz->iparam[MIX_STTA]) - dz->iparam[MIX_STAGGER]; if((cutoff_samps) <= 0) cutoff_samps = UINT_MAX; while(gross_samps_read > 0) { memset((char *)inbuf1,0,(size_t)(dz->buflen * sizeof(float))); memset((char *)inbuf2,0,(size_t)(dz->buflen * sizeof(float))); memset((char *)dblbuf,0,(size_t)(dz->buflen * sizeof(double))); if((samps_read1 = fgetfbufEx(inbuf1,dz->buflen,dz->ifd[0],0))<0) { sprintf(errstr,"Problem reading from file1 during mix.\n"); return(SYSTEM_ERROR); } if((samps_read2 = fgetfbufEx(inbuf2,dz->buflen,dz->ifd[1],0))<0) { sprintf(errstr,"Problem reading from file1 during mix.\n"); return(SYSTEM_ERROR); } if((gross_samps_read = max(samps_read1,samps_read2))<=0) break; gross_total_samps_read += gross_samps_read; if(cutoff_samps > (unsigned int) gross_total_samps_read) cutoff_in_buf = gross_samps_read; else cutoff_in_buf = (cutoff_samps % dz->buflen); ssampsread1 = samps_read1; ssampsread1 = min(ssampsread1,cutoff_in_buf); if(ssampsread1) { for(n=0;nparam[MIX2_GAIN1]; if((ssampsread2 = samps_read2)>0) { ssampsread2 = min(ssampsread2,cutoff_in_buf); for(n=0;nparam[MIX2_GAIN2]; } } else { ssampsread2 = samps_read2; ssampsread2 = min(ssampsread2,cutoff_in_buf); for(n=0;nparam[MIX2_GAIN2]; } ssampsread = gross_samps_read; ssampsread = min(ssampsread,cutoff_in_buf); for(n=0;n 0) { if((exit_status = write_samps(obuf,ssampsread,dz))<0) return(exit_status); } if((unsigned int)gross_total_samps_read >= cutoff_samps) break; } return(FINISHED); } /******************************** MIX_CROSS **********************************/ int mix_cross(dataptr dz) { int exit_status; float *inbuf1 = dz->sampbuf[0]; float *inbuf2 = dz->sampbuf[1]; float *obuf = dz->sampbuf[0]; int samps_read2 = 0; int end_of_samps_to_process = dz->iparam[MCR_END]; int cross_end = 0; int total_samps_read = 0; int remain; if(end_of_samps_to_process <= 0) { sprintf(errstr,"Accounting problem: mix_cross()\n"); return(PROGRAM_ERROR); } display_virtual_time(0,dz); if(dz->iparam[MCR_STAGGER]>0 && (exit_status = cross_stagger(&total_samps_read,&end_of_samps_to_process,obuf,dz))<0) return(exit_status); if(end_of_samps_to_process <=0) { sprintf(errstr,"Accounting problem 1: mix_cross()\n"); return(PROGRAM_ERROR); } while(total_samps_read <= dz->iparam[MCR_BEGIN]) { if((exit_status = pre_crossmix (&samps_read2,&cross_end,&total_samps_read,&end_of_samps_to_process,inbuf1,inbuf2,obuf,dz))<0) return(exit_status); if(exit_status == FINISHED) break; } if(end_of_samps_to_process <=0) { sprintf(errstr,"Accounting problem 2: mix_cross()\n"); return(PROGRAM_ERROR); } remain = samps_read2 - end_of_samps_to_process; if(remain < 0) { do { if((exit_status = crossmix (&samps_read2,&cross_end,&total_samps_read,&end_of_samps_to_process,inbuf1,inbuf2,obuf,dz))<0) return(exit_status); } while((remain = samps_read2 - end_of_samps_to_process) < 0); } if(remain) memmove((char *)(obuf + cross_end),(char *)(inbuf2 + cross_end),(size_t)(remain * sizeof(float))); if(samps_read2 > 0) { if((exit_status = write_samps(obuf,samps_read2,dz))<0) return(exit_status); } while((samps_read2 = fgetfbufEx(obuf, dz->buflen,dz->ifd[1],0))>0) { if((exit_status = write_samps(obuf,samps_read2,dz))<0) return(exit_status); } if(samps_read2<0) { sprintf(errstr,"Sound read error.\n"); return(SYSTEM_ERROR); } return(FINISHED); } /******************************** CROSS **********************************/ int cross(int startcross,int endcross,float *inbuf1,float *inbuf2,float *obuf,dataptr dz) { double xxx, yyy; register int i; int crosindex = dz->iparam[MCR_INDEX]; double crosfact = dz->param[MCR_CROSFACT]; double powfac; switch(dz->iparam[MCR_CONTOUR]) { case(MCR_LINEAR): /* LINEAR */ for(i=startcross;iparam[MCR_POWFAC]; for(i=startcross;iiparam[MCR_INDEX] = crosindex; return(FINISHED); } /************************** READ_COS **********************/ double read_cos(double d,dataptr dz) { int j, k; double frac, diff; double *costable = dz->parray[MCR_COSTABLE]; d *= (double)MCR_TABLEN; j = (int)d; /* TRUNCATE */ if((k=j+1)>MCR_TABLEN) return(1.0); frac = d - (double)j; diff = costable[k] - costable[j]; frac *= diff; return(costable[j] + frac); } /************************** CROSSMIX **********************/ int crossmix(int *samps_read2,int *cross_end,int *total_samps_read,int *end_of_samps_to_process, float *inbuf1,float *inbuf2,float *obuf,dataptr dz) { int exit_status; if((exit_status = advance_in_files (samps_read2,total_samps_read,end_of_samps_to_process,cross_end,inbuf1,inbuf2,dz))<0) return(exit_status); *cross_end = min(*cross_end,dz->buflen); if((exit_status = cross(0L,*cross_end,inbuf1,inbuf2,obuf,dz))<0) return(exit_status); if(*cross_end==dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); } return(FINISHED); } /************************** PRE_CROSSMIX **********************/ int pre_crossmix(int *samps_read2,int *cross_end,int *total_samps_read, int *end_of_samps_to_process,float *inbuf1,float *inbuf2,float *obuf,dataptr dz) { int exit_status; int ssampstart, cross_start; int last_total_samps_read = *total_samps_read; if((exit_status = advance_in_files (samps_read2,total_samps_read,end_of_samps_to_process,cross_end,inbuf1,inbuf2,dz))<0) return(exit_status); if(*total_samps_read > dz->iparam[MCR_BEGIN]) { if((cross_start = dz->iparam[MCR_BEGIN] - last_total_samps_read)>=dz->buflen) { sprintf(errstr,"Accounting problem: pre_crossmix()\n"); return(PROGRAM_ERROR); } ssampstart = cross_start; *cross_end = min(*cross_end,dz->buflen); if((exit_status = cross(ssampstart,*cross_end,inbuf1,inbuf2,obuf,dz))<0) return(exit_status); if(*cross_end < dz->buflen) return(FINISHED); } if((exit_status= write_samps(obuf,dz->buflen,dz))<0) return(exit_status); return(CONTINUE); } /************************** CROSS_STAGGER **********************/ int cross_stagger(int *total_samps_read,int *end_of_samps_to_process,float *obuf,dataptr dz) { int exit_status; int samps_read1, samps_written; int stagger = dz->iparam[MCR_STAGGER]; int stagbufs = stagger/dz->buflen; int stagsamps = stagger%dz->buflen; //TW SAFE?? // if(((stagsamps/F_SECSIZE)*F_SECSIZE)!=stagsamps) { // sprintf(errstr,"Sector accounting problem: cross_stagger()\n"); // return(PROGRAM_ERROR); // } while(stagbufs>0) { if((samps_read1 = fgetfbufEx(obuf, dz->buflen,dz->ifd[0],0))!=dz->buflen) { if(samps_read1<0) { sprintf(errstr,"Sound read error.\n"); return(SYSTEM_ERROR); } else { sprintf(errstr,"First file read failed:1: cross_stagger()\n"); return(PROGRAM_ERROR); } } // if((samps_written = fputfbufEx(obuf,dz->buflen,dz->ofd))!=dz->buflen) { if((exit_status = write_samps_no_report(obuf,dz->buflen,&samps_written,dz))<0) return(exit_status); if(samps_written!=dz->buflen) { sprintf(errstr,"Problem writing samps:1: cross_stagger()\n"); return(PROGRAM_ERROR); } dz->total_samps_written += samps_written; *total_samps_read += dz->buflen; *end_of_samps_to_process -= dz->buflen; stagbufs--; } if(stagsamps > 0) { if((samps_read1 = fgetfbufEx(obuf, stagsamps,dz->ifd[0],0))!=stagsamps) { if(samps_read1<0) { sprintf(errstr,"Sound read error.\n"); return(SYSTEM_ERROR); } else { sprintf(errstr,"First file read failed:2: cross_stagger()\n"); return(PROGRAM_ERROR); } } // if((samps_written = fputfbufEx(obuf,stagsamps,dz->ofd))!=stagsamps) { if((exit_status = write_samps_no_report(obuf,stagsamps,&samps_written,dz) )< 0) return(exit_status); if(samps_written != stagsamps) { sprintf(errstr,"Problem writing samps:2: cross_stagger()\n"); return(PROGRAM_ERROR); } dz->total_samps_written += stagsamps; *total_samps_read += stagsamps; *end_of_samps_to_process -= stagsamps; } return(FINISHED); } /************************** ADVANCE_IN_FILES **********************/ int advance_in_files(int *samps_read2,int *total_samps_read,int *end_of_samps_to_process, int *cross_end,float *inbuf1,float *inbuf2,dataptr dz) { int samps_read1; *end_of_samps_to_process = dz->iparam[MCR_END] - *total_samps_read; if((samps_read1 = fgetfbufEx(inbuf1, dz->buflen,dz->ifd[0],0))<0) { sprintf(errstr,"First file read failed: advance_in_files()\n"); return(SYSTEM_ERROR); } if((*samps_read2 = fgetfbufEx(inbuf2, dz->buflen,dz->ifd[1],0))<0) { sprintf(errstr,"Second file read failed: advance_in_files()\n"); return(SYSTEM_ERROR); } *total_samps_read += *samps_read2; /* BECAUSE FADE IS TOWARDS FILE 2: and fade must END before then */ *cross_end = *end_of_samps_to_process; return(FINISHED); } /************************************ MIX_INTERL ************************************/ int mix_interl(dataptr dz) { int exit_status; float *inbuf = dz->sampbuf[0]; float *outbuf = dz->sampbuf[1]; /* NB this buffer is large enough to take output */ int samps_read, samps_left[MAX_MI_OUTCHANS]; int n, gross_samps_read, gross_samps_left = 0, last_total_samps_written, samps_to_write; for(n=0;ninfilecnt;n++) { samps_left[n] = dz->insams[n]; gross_samps_left = max(gross_samps_left,samps_left[n]); } while(gross_samps_left) { memset((char *)outbuf,0,(size_t)(dz->buflen * dz->infilecnt * sizeof(float))); gross_samps_read = 0; gross_samps_left = 0; for(n=0;ninfilecnt;n++) { if(samps_left[n]>0) { if((samps_read = fgetfbufEx(inbuf,dz->buflen,dz->ifd[n],0))<0) { sprintf(errstr,"Failed to read data from file %d: mix_interl()\n",n+1); return(SYSTEM_ERROR); } samps_left[n] -= samps_read; copy_to_channel(inbuf,outbuf+n,samps_read,dz->infilecnt); gross_samps_read = max(gross_samps_read,samps_read); gross_samps_left = max(gross_samps_left,samps_left[n]); } } samps_to_write = gross_samps_read*dz->infilecnt; last_total_samps_written = dz->total_samps_written; if(samps_to_write) { if((exit_status = write_samps(outbuf,samps_to_write,dz))<0) return(exit_status); } if(dz->total_samps_written - last_total_samps_written != samps_to_write) { sprintf(errstr,"Problem writing data: mix_interl()\n"); return(PROGRAM_ERROR); } } // TW // /*RWD too late here! */ // dz->infile->channels = dz->infilecnt; /* Force output to final channel-count */ return(FINISHED); } /************************************ COPY_TO_CHANNEL ************************************/ void copy_to_channel(float *inbuf,float *outbuf,int sampcnt,int outchans) { int n, m; for(n=0,m=0;ninfile->srate; int n = 0, mbf, sbf, procend, input_procend; int exit_status, t = 0,v=0,m=0,done = 0; double *brrk = NULL, thisval, nextval = 0.0, valincr, atten = 0.0, val_here; double time_here, lastrtime,nextrtime, lastval, tratio; int nexttime = 0, thistime; float *buf0 = dz->sampbuf[0]; float *buf1 = dz->sampbuf[1]; int typ; int input_procskip, samps_to_skip = 0; if(dz->param[MIX_SKEW] <= dz->param[MIX_SKIP]) { sprintf(errstr,"Start and end times of mix are reversed, or equal.\n"); return(DATA_ERROR); } /* RWD make this samps */ dz->tempsize = (int)round((dz->param[MIX_SKEW] - dz->param[MIX_SKIP]) * (double)(srate * max(dz->infile->channels,dz->otherfile->channels))); display_virtual_time(0,dz); if(dz->infile->channels > 2) { typ = 4; /* multichan multichan */ } else if(dz->infile->channels==1) { if(dz->otherfile->channels==1) { typ = 0; /* mono mono */ } else { typ = 1; /* mono stereo */ } } else { if(dz->otherfile->channels==1) { typ = 2; /* stereo mono */ } else { typ = 3; /* stereo stereo */ } } procend = dz->insams[0]/dz->infile->channels; input_procend = (int)round(dz->param[MIX_SKEW] * srate); procend = min(procend,input_procend); if((input_procskip = (int)round(dz->param[MIX_SKIP] * srate)) > 0) { samps_to_skip = input_procskip * dz->infile->channels; //TW SAFE?? // samps_to_skip /= (F_SECSIZE * dz->infile->channels); // samps_to_skip *= (F_SECSIZE * dz->infile->channels); /* skip to nearest sector */ if((sndseekEx(dz->ifd[0],samps_to_skip,0))<0) { sprintf(errstr,"seek() failed searching for startpoint of mix in first file.\n"); return(SYSTEM_ERROR); } samps_to_skip = input_procskip * dz->otherfile->channels; //TW SAFE?? // samps_to_skip /= (F_SECSIZE * dz->otherfile->channels); // samps_to_skip *= (F_SECSIZE * dz->otherfile->channels); /* skip to nearest sector */ if((sndseekEx(dz->ifd[1],samps_to_skip,0))<0) { sprintf(errstr,"sndseek() failed searching for startpoint of mix in second file.\n"); return(SYSTEM_ERROR); } } if(dz->brksize[MIX_STAGGER]) { brrk = dz->brk[MIX_STAGGER]; if(input_procskip > 0) { thistime = samps_to_skip/dz->otherfile->channels; time_here = (double)thistime/srate; m = 0; while(brrk[m] <= time_here) { m += 2; if(m >= dz->brksize[MIX_STAGGER]) { /* IF beyond end of brk */ dz->param[MIX_STAGGER] = brrk[m-1]; /* set atten to last brkval */ dz->brksize[MIX_STAGGER] = 0; /* set brkfile as not existing */ break; } } if(dz->brksize[MIX_STAGGER]) { /* If still in brkfile */ lastrtime = brrk[m-2]; /* Note previous brkpnt-time+val */ lastval = brrk[m-1]; n = thistime; /* set the internal sample counter to here */ t = m; /* set pointer for (following) brkpnt times */ v = m+1; /* set pointer for (following) brkpnt vals */ m /= 2; /* set position in brk-pairs */ nextrtime = brrk[t]; nexttime = round(nextrtime * srate); nextval = brrk[v]; /* calc value at start-time */ tratio = (double)(time_here - lastrtime)/(double)(nextrtime - lastrtime); val_here = ((nextval - lastval) * tratio) + lastval; nexttime = thistime; /* set up starting time & val */ nextval = val_here; } } else { nexttime = round(brrk[0] * srate); nextval = brrk[1]; /* set up starting time & val */ n = 0; /* set the internal sample counter to start */ t = 2; /* set pointer for (following) brkpnt times */ v = 3; /* set pointer for (following) brkpnt vals */ m = 1; /* set position in brk-pairs */ } } else { n = input_procskip; } memset((char *)buf0,0,dz->buflen * dz->infile->channels* sizeof(float)); memset((char *)buf1,0,dz->buflen * dz->otherfile->channels * sizeof(float)); if((fgetfbufEx(buf0,dz->buflen * dz->infile->channels,dz->ifd[0],0)) < 0) { sprintf(errstr,"Can't read samps from 1st soundfile.\n"); return(SYSTEM_ERROR); } if((fgetfbufEx(buf1,dz->buflen * dz->otherfile->channels,dz->ifd[1],0)) < 0) { sprintf(errstr,"Can't read samps from 2nd soundfile.\n"); return(SYSTEM_ERROR); } mbf = 0; sbf = 0; if(dz->brksize[MIX_STAGGER] == 0) atten = dz->param[MIX_STAGGER]; else { for(; m < dz->brksize[MIX_STAGGER]; m++,t+=2,v+=2) { thistime = nexttime; thisval = nextval; nexttime = round(brrk[t] * srate); nextval = brrk[v]; valincr = (nextval - thisval)/(double)(nexttime - thistime); if(nexttime >= procend) { /* IF brktable extends beyond end of sound */ nexttime = procend; done = 1; } atten = thisval; while(n < nexttime) { if(do_stitch(typ,&mbf,&sbf,buf0,buf1,atten,dz->buflen,dz)) { if((exit_status = renew_bufs(typ,buf0,buf1,dz))<0) return(exit_status); mbf = 0; sbf = 0; } atten += valincr; n++; } if(done) /* IF brktable extends beyond end of sound: break */ break; } } while(n < procend) { /* IF brktable stops short of end of sound, or no brktable */ if(do_stitch(typ,&mbf,&sbf,buf0,buf1,atten,dz->buflen,dz)) { if((exit_status = renew_bufs(typ,buf0,buf1,dz))<0) return(exit_status); mbf = 0; sbf = 0; } n++; } return flush_bufs(typ,&mbf,&sbf,buf0,buf1,dz); } /******************************** DO_STITCH *****************************/ int do_stitch(int typ,int *mbf,int *sbf,float *buf0,float *buf1,double atten,int bflen,dataptr dz) { int bufdone = 0, k; switch(typ) { case(0): buf0[*mbf] = (float)((buf0[*mbf] * atten) + (buf1[*mbf] * (1.0 - atten))); if(++(*mbf) >= bflen) bufdone = 1; break; case(1): buf1[*sbf] = (float)((buf0[*mbf] * atten) + (buf1[*sbf] * (1.0 - atten))); (*sbf)++; buf1[*sbf] = (float)((buf0[*mbf] * atten) + (buf1[*sbf] * (1.0 - atten))); (*sbf)++; if(++(*mbf) >= bflen) bufdone = 1; break; case(2): buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*mbf] * (1.0 - atten))); (*sbf)++; buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*mbf] * (1.0 - atten))); (*sbf)++; if(++(*mbf) >= bflen) bufdone = 1; break; case(3): buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*sbf] * (1.0 - atten))); (*sbf)++; buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*sbf] * (1.0 - atten))); if(++(*sbf) >= bflen * 2) bufdone = 1; break; case(4): for(k=0; k < dz->infile->channels; k++) { buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*sbf] * (1.0 - atten))); (*sbf)++; } if(*sbf >= bflen * dz->infile->channels) bufdone = 1; break; } return(bufdone); } /******************************** RENEW_BUFS *****************************/ int renew_bufs(int typ,float *buf0,float *buf1,dataptr dz) { int exit_status; switch(typ) { case(0): if((exit_status = write_samps(buf0,dz->buflen,dz))<0) return(exit_status); memset((char *)buf0,0,dz->buflen * sizeof(float)); memset((char *)buf1,0,dz->buflen * sizeof(float)); break; case(1): if((exit_status = write_samps(buf1,dz->buflen * 2,dz))<0) return(exit_status); memset((char *)buf0,0,dz->buflen * sizeof(float)); memset((char *)buf1,0,dz->buflen * 2 * sizeof(float)); break; case(2): if((exit_status = write_samps(buf0,dz->buflen * 2,dz))<0) return(exit_status); memset((char *)buf0,0,dz->buflen * 2 * sizeof(float)); memset((char *)buf1,0,dz->buflen * sizeof(float)); break; case(3): if((exit_status = write_samps(buf0,dz->buflen * 2,dz))<0) return(exit_status); memset((char *)buf0,0,dz->buflen * 2 * sizeof(float)); memset((char *)buf1,0,dz->buflen * 2 * sizeof(float)); break; case(4): if((exit_status = write_samps(buf0,dz->buflen * dz->infile->channels,dz))<0) return(exit_status); memset((char *)buf0,0,dz->buflen * dz->infile->channels * sizeof(float)); memset((char *)buf1,0,dz->buflen * dz->otherfile->channels * sizeof(float)); break; } if((fgetfbufEx(buf0,dz->buflen * dz->infile->channels,dz->ifd[0],0)) < 0) { sprintf(errstr,"Can't read samps from 1st soundfile.\n"); return(SYSTEM_ERROR); } if((fgetfbufEx(buf1,dz->buflen * dz->otherfile->channels,dz->ifd[1],0)) < 0) { sprintf(errstr,"Can't read samps from 2nd soundfile.\n"); return(SYSTEM_ERROR); } return(FINISHED); } /******************************** FLUSH_BUFS *****************************/ int flush_bufs(int typ,int *mbf,int *sbf,float *buf0,float *buf1,dataptr dz) { int exit_status; switch(typ) { case(0): /* Output file takes its channel cnt from 1st input file : HENCE.... */ if(*mbf > 0) { if((exit_status = write_samps(buf0,*mbf,dz))<0) return(exit_status); } /* 1st input file MONO : output file MONO */ break; case(1): if(*sbf > 0) { if((exit_status = write_samps(buf1,*sbf,dz))<0) return(exit_status); } /* 1st input file MONO : output file STEREO */ dz->infile->channels = 2; /* Force output file to have stereo header */ break; case(2): /* 1st input file STEREO : output file STEREO */ case(3): case(4): if(*sbf > 0) { if((exit_status = write_samps(buf0,*sbf,dz))<0) return(exit_status); } break; } return(FINISHED); } //TW JANUARY 2010: MODIFIED FOR MULTICHANNEL /*************************** DO_AUTOMIX *******************************/ int do_automix(dataptr dz) { double srate = (double)dz->infile->srate; unsigned int nexttime, thistime, outcnt = 0, bufcnt = 0; int outchans = 1, exit_status; double *p = dz->parray[0], *arrayend = dz->parray[0] + dz->itemcnt; double *thislevel, *nextlevel, *incr, sum, convertor_to_time, convertor_to_smps; int *activebuf, overflows = 0; unsigned int max_insams = 0; int *chans, n; // RWD 2025 now use calloc to pacify gcc if((chans = (int *) calloc(dz->infilecnt, sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory for level stores\n"); return(MEMORY_ERROR); } if((thislevel = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for level stores\n"); return(MEMORY_ERROR); } if((nextlevel = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for level stores\n"); return(MEMORY_ERROR); } if((incr = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for level stores\n"); return(MEMORY_ERROR); } if((activebuf = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory for level stores\n"); return(MEMORY_ERROR); } for(n=0;ninfilecnt;n++) { activebuf[n] = 1; if(sndgetprop(dz->ifd[n],"channels", (char *)&(chans[n]), sizeof(int)) < 0) { sprintf(errstr,"Failure to read channel data, for input file %d\n",n+1); return(DATA_ERROR); } if(n>0 && chans[n] != chans[0]) { sprintf(errstr,"Process only works with files having the same number of channels: file %d will not work\n",n+1); return(DATA_ERROR); } } outchans = chans[0]; convertor_to_smps = srate * outchans; convertor_to_time = 1.0/convertor_to_smps; for(n=0;ninfilecnt;n++) max_insams = max(max_insams,(unsigned int)dz->insams[n]); dz->tempsize = max_insams; /* for scrollbar display */ if((exit_status = create_sized_outfile(dz->outfilename,dz))<0) return(exit_status); if((exit_status = read_automix_sound(activebuf,dz))<0) return(exit_status); nexttime = (unsigned int)round(*p++ * convertor_to_smps); for(n = 0;ninfilecnt; n++) nextlevel[n] = *p++; while(outcnt < max_insams) { thistime = nexttime; /* establish amplitude ramps */ for(n = 0; ninfilecnt; n++) thislevel[n] = nextlevel[n]; if(p < arrayend) { nexttime = (unsigned int)round(*p++ * convertor_to_smps); for(n = 0;ninfilecnt; n++) { nextlevel[n] = *p++; incr[n] = (nextlevel[n] - thislevel[n])/(double)(nexttime - thistime); } } else { /* if amp-data runs out */ for(n = 0;ninfilecnt; n++) /* set amp increments to zero */ incr[n] = 0.0; nexttime = max_insams; /* and proceed to end of file */ } nexttime = min(nexttime, max_insams); /* if snd-data runs out, curtail loop to snd-data end */ while(outcnt < nexttime) { sum = 0.0; for(n=0;ninfilecnt;n++) { if(activebuf[n]) { sum += dz->sampbuf[n][bufcnt] * thislevel[n]; thislevel[n] += incr[n]; if(outcnt >= (unsigned int)dz->insams[n]) activebuf[n] = 0; } } if(fabs(sum) > F_MAXSAMP) overflows++; dz->sampbuf[dz->infilecnt][bufcnt] = (float)(sum * dz->param[0]); if(++bufcnt >= (unsigned int)dz->buflen) { if((exit_status = write_samps(dz->sampbuf[dz->infilecnt],dz->buflen,dz))<0) return(exit_status); if((exit_status = read_automix_sound(activebuf,dz))<0) return(exit_status); bufcnt = 0; } outcnt++; if(dz->brksize[0]) { if((exit_status = read_value_from_brktable((double)outcnt * convertor_to_time,0,dz))<0) return(exit_status); } } } if(bufcnt) { if((exit_status = write_samps(dz->sampbuf[dz->infilecnt],bufcnt,dz))<0) return(exit_status); } if(overflows) { fprintf(stdout,"WARNING: %d samples were clipped.\n",overflows); fflush(stdout); } return(FINISHED); } /*************************** READ_AUTOMIX_SOUND *******************************/ int read_automix_sound(int *activebuf,dataptr dz) { int n; for(n=0;ninfilecnt;n++) { if(!activebuf[n]) /* only read from files with data remaining */ continue; if((dz->ssampsread = fgetfbufEx(dz->sampbuf[n],dz->buflen,dz->ifd[n],0)) < 0) { sprintf(errstr,"Can't read samps from input soundfile %d.\n",n+1); return(SYSTEM_ERROR); } } return(FINISHED); } /************************************ MIXMANY ************************************/ int mixmany(dataptr dz) { int exit_status; int gross_samps_read, n, m; int ssampsread; double *dblbuf = (double *)dz->sampbuf[2], maxdsamp = 0.0; float *ibuf = dz->sampbuf[0]; float *obuf = dz->sampbuf[1]; dz->tempsize = 0; for(n=0;n<=dz->infilecnt;n++) dz->tempsize = max(dz->tempsize,dz->insams[n]); display_virtual_time(0L,dz); fprintf(stdout,"INFO: Finding maximum level\n"); fflush(stdout); do { memset((char *)ibuf,0,(size_t)dz->buflen * sizeof(float)); memset((char *)dblbuf,0,(size_t)dz->buflen * sizeof(double)); gross_samps_read = 0; for(n=0;ninfilecnt;n++) { if((ssampsread = fgetfbufEx(ibuf,dz->buflen,dz->ifd[n],0))<0) { sprintf(errstr,"Problem reading from file %d\n",n+1); return(SYSTEM_ERROR); } gross_samps_read = max(gross_samps_read,ssampsread); if(ssampsread > 0) { for(m=0;m 0); maxdsamp = F_MAXSAMP/maxdsamp; for(n=0;ninfilecnt;n++) { if(sndseekEx(dz->ifd[n],0,0)<0) { sprintf(errstr,"seek failed for file %d\n",n+1); return(SYSTEM_ERROR); } } dz->total_samps_written = 0; display_virtual_time(0,dz); fprintf(stdout,"INFO: Doing the mix.\n"); fflush(stdout); do { memset((char *)ibuf,0,(size_t)dz->buflen * sizeof(float)); memset((char *)dblbuf,0,(size_t)dz->buflen * sizeof(double)); gross_samps_read = 0; for(n=0;ninfilecnt;n++) { if((ssampsread = fgetfbufEx(ibuf,dz->buflen,dz->ifd[n],0))<0) { sprintf(errstr,"Problem reading from file %d during mix.\n",n+1); return(SYSTEM_ERROR); } gross_samps_read = max(gross_samps_read,ssampsread); if(ssampsread > 0) { for(m=0;m 0); return(FINISHED); }