/* * 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 #include #include #include #include #include #include #include #include #include #include //TW UPDATE #include #include #include #include #define INBUF_START (0) #define OUTBUF_START (1) #define OUTBUF_END (2) //#ifdef unix #define round(x) lround((x)) //#endif static int init_outbuf (int startsamp,int *is_simple,int *write_offset,int *samp_offset,int *samps_left_to_process,dataptr dz); static int init_brkpnts (int *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk, double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz); static int advance_brkpnts (double starttime,double *gain,double *endbrk,double **nextbrk,double *nextgain, double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz); static int calc_samps_to_process (int *startsamp,int *samps_left_to_process,dataptr dz); static int simple_envel_processing (int *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain, int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz); static int buf_staggered_envel_processing (int *samps_left_to_process,int samp_offset,int write_offset,double starttime,double *endbrk,double **nextbrk, double *nextgain,int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz); static int read_partbuf_samps (int samps_to_read,int *samps_left_to_process, dataptr dz); static int do_envelope (int samp_cnt,double starttime,double *endbrk,double **nextbrk,double *nextgain, int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz); static int read_ssamps(int samps_to_read,int *samps_left_to_process,dataptr dz); static int do_simple_read(int *samps_left_to_process,int bufsize,dataptr dz); static int do_offset_read(int *samps_left_to_process,int samp_offset,int bufsize,dataptr dz); static int skip_into_file(int startsamp,int extended_buf_sampsize,int *write_offset,int *samp_offset,dataptr dz); /******************************* APPLY_BRKPNT_ENVELOPE *******************************/ int apply_brkpnt_envelope(dataptr dz) { int exit_status; int startsamp, samps_left_to_process; int is_simple; int write_offset, samp_offset, sampno, nextbrk_sampno; double starttime, gain, nextgain, gain_step, gain_incr; double *endbrk, *nextbrk; if((exit_status = calc_samps_to_process(&startsamp,&samps_left_to_process,dz))<0) return(exit_status); if((exit_status = init_outbuf(startsamp,&is_simple,&write_offset,&samp_offset,&samps_left_to_process,dz))<0) return(exit_status); if((exit_status = init_brkpnts (&sampno,&starttime,&gain,&endbrk,&nextbrk,&nextgain,&gain_step,&gain_incr,&nextbrk_sampno,dz))<0) return(exit_status); exit_status = FINISHED; if(is_simple) exit_status = simple_envel_processing (&samps_left_to_process,starttime,endbrk,&nextbrk,&nextgain, &sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,dz); else exit_status = buf_staggered_envel_processing (&samps_left_to_process,samp_offset,write_offset,starttime,endbrk,&nextbrk, &nextgain,&sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,dz); return(exit_status); } /**************************** INIT_OUTBUF ******************************* * * |-------------extended-buffer-size-----------| * X * |-------------buffer-size---------------| * INBUF * |----|----|----|----|----|----|----|----|----| * | | | * | | | | write (=write offset offset) * | | | | * | | | * samp | * offset | * | | | * |----|----|----|----|----|----|----|----| * OUTBUF * |-------------buffer-size---------------| * * IF the brkpoint table starts at 0, * we can use THE SAME buffer for input and output. * OTHERWISE......... * (8) First extimate of the number of samples in the input file which * we can skip, i.e. the number of complete extended-buffer-fulls * (see diagram) we can read before reaching first significant sample. * (9) After counting out these, we can assess how many COMPLETED sectors * are still to be read and ignored. * (10) We can now add the number of samples in these sectors to our first * estimate of samples to be skipped. * (11) The extent to which the OUTPUT buffer will be offset from the * INPUT buffer, (samp_offset) is given by the remaining part-sector of samps. * (see diagram). * (12) After the initial write, we will WRITE to a block 1 SECTOR later, * (X in diagram), so the WRITE-OFFSET is as shown. * (13) We now SEEK an exact number of sectors in the input file (thus * discarding these samps from our processing). * (14) If the samp_offset is ZERO, then we input and output buffers are * the same as at 4,5,6. * (16) Otherwise, fill the EXTENDED buffer (see diagram). * (17) Move the address of future read-ins (inbuf) 1 sector forward (to X in diagram). * (18) Set the address of the read-out buffer at the correct offset. * (19) Set the flag for the more difficult case. * (20) Decrement number of samps left to process. * If this takes samps_left below zero, this means we have * read a whole sector in place of a part-sector, so we must * readjust the value of samps_read!! */ int init_outbuf(int startsamp,int *is_simple,int *write_offset, int *samp_offset,int *samps_left_to_process,dataptr dz) { int exit_status; int extended_buf_sampsize = dz->buflen; int shsecsize = F_SECSIZE; /*RWD: set the vars*/ *samp_offset = *write_offset = 0; if(startsamp==0) { /* If we start at beginning */ dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START]; /* inbuf and outbuf coincide */ if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0) return(exit_status); /* setup simple buffering option */ *is_simple = TRUE; } else { if((exit_status = skip_into_file(startsamp,extended_buf_sampsize,write_offset,samp_offset,dz))<0) return(exit_status); /* calculate sectors to skip into file, and any part-sector offset, and skip */ if(*samp_offset==0) { /* If no offset */ dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START];/* inbuf and outbuf coincide */ if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0) return(exit_status); *is_simple = TRUE; } else { /* Otherwise there is an offset */ if((exit_status = do_offset_read(samps_left_to_process,*samp_offset, /*dz->bigbufsize + SECSIZE*/dz->buflen,dz))<0) return(exit_status); /* read initial LARGE buffer */ dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START] + *samp_offset; /* Set outbuf (write) position */ dz->sampbuf[OUTBUF_END] = dz->sampbuf[OUTBUF_START] + dz->buflen; /* Set endpointer of outbuf */ dz->sampbuf[INBUF_START] += shsecsize; /* Set next read position for inbuf */ /* to permit correct wrap_around of part_sector */ *is_simple = FALSE; /* Flag staggerd-buffers option */ } } return(FINISHED); } /**************************** INIT_BRKPNTS ******************************* * NB Here samples are taken to be a short for mono, 2 shorts for stereo, etc. * and times are measured in such 'samples'. */ int init_brkpnts(int *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk, double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz) { double nexttime, time_from_start; int paramno = dz->extrabrkno; *endbrk = dz->brk[paramno] + ((dz->brksize[paramno]-1) * 2); *sampno = 0; *starttime = dz->brk[paramno][0]; *gain = dz->brk[paramno][1]; *nextbrk = dz->brk[paramno] + 2; nexttime = **nextbrk; *nextgain = *((*nextbrk) + 1); *gain_step = *nextgain - *gain; time_from_start = nexttime - *starttime; /* OCT 1996 */ if((*nextbrk_sampno = (int)round(time_from_start * (double)dz->infile->srate))<0) { sprintf(errstr,"Impossible brkpoint time: (%.2lf secs)\n",time_from_start); return(PROGRAM_ERROR); } *gain_incr = (*gain_step)/(double)(*nextbrk_sampno); return(FINISHED); } /**************************** ADVANCE_BRKPNTS ***************************** * NB Here samples are taken to be a short for mono, 2 shorts for stereo, etc. * and times are measured in such 'samples'. */ int advance_brkpnts(double starttime,double *gain,double *endbrk,double **nextbrk, double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz) { double nexttime, time_from_start; int lastbrk_sampno, sampdist; if(*nextbrk!=endbrk) { *nextbrk += 2; *gain = *nextgain; nexttime = **nextbrk; *nextgain = *((*nextbrk) + 1); *gain_step = *nextgain - *gain; lastbrk_sampno = *nextbrk_sampno; time_from_start = nexttime - starttime; /* OCT 1996 */ if((*nextbrk_sampno = (int)round(time_from_start * dz->infile->srate))<0) { sprintf(errstr,"Impossible brkpoint time: (%.2lf secs)\n",time_from_start); return(PROGRAM_ERROR); } sampdist = *nextbrk_sampno - lastbrk_sampno; *gain_incr = (*gain_step)/(double)sampdist; } return(FINISHED); } /************************ CALC_SAMPS_TO_PROCESS **************************** * * (1) Find time of final breakpoint value. * (a) Find the sample position of the brkpoint-table's starting time. * (b) Find its samp position. * (2) Find this time in samples (here samples mean short samples). * (3) The last samp to be processed is either the samp corresponding * to the last sample-time in brkpnt file OR the end of the input file. * (4) Number of samps-to-process = endsamp-time - startsamp-time. * (5) This also gives the required size of output file. */ int calc_samps_to_process(int *startsamp,int *samps_left_to_process,dataptr dz) { int paramno = dz->extrabrkno; int endbrk_samptime, endsamp, start_samp; double lastbrktime, firstbrktime; double infiledur = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate; lastbrktime = *(dz->brk[paramno] + ((dz->brksize[paramno] - 1) * 2)); if(flteq(lastbrktime,infiledur)) { endsamp = dz->insams[0]; } else { endbrk_samptime = round(lastbrktime * (double)dz->infile->srate); endbrk_samptime *= dz->infile->channels; endsamp = min((int)endbrk_samptime,dz->insams[0]); } firstbrktime = *(dz->brk[paramno]); *startsamp = round(firstbrktime * (double)dz->infile->srate); *startsamp *= dz->infile->channels; if((start_samp = *startsamp ) >= dz->insams[0]) { sprintf(errstr,"envelope begins after end of file: can't proceed.\n"); return(DATA_ERROR); } *samps_left_to_process = endsamp - start_samp; return(FINISHED); } /*********************** SIMPLE_ENVEL_PROCESSING ******************************** * * Simple case, input and output buffers coincide. * * (1) If we read beyond number of samps we anticipated, this means * we have read to the end of a sector, where we need a part-sector, * so we must adjust value of actual samps read!!! */ int simple_envel_processing (int *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain, int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz) { int exit_status; while(*samps_left_to_process > 0) { if((exit_status = do_envelope (dz->buflen,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0) return(exit_status); if((exit_status = write_samps(dz->sampbuf[OUTBUF_START],dz->buflen,dz))<0) return(exit_status); if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0) return(exit_status); } if((exit_status = do_envelope (dz->ssampsread,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0) return(exit_status); if(dz->ssampsread > 0) return write_samps(dz->sampbuf[OUTBUF_START],dz->ssampsread,dz); return(FINISHED); } /*********************** BUF_STAGGERED_ENVEL_PROCESSING ******************************** * * Non-simple case, input and output buffers do not coincide. * * ___________tail is copied thus_________ * | | * | | * v INBUF ^ * |----|----|----|----|----|----|----|----|----| * | | * | | | | * write_offset tail * | | | | * | | * |----|----|----|----|----|----|----|----| * OUTBUF * * (1) If we are inside the loop, there are still samps left to read * from input file, so this input buffer must be FULL. * This means we can WRITE a full output-buffer. * (2) Copy the tail-portion of the input buffer (that falls outside the * end of the output buffer (see diagram)), to the start of the output buffer (see diagram). * (3) Read samps to inbuf location, decrementing no of samps left to read. * (4) If first time, (No buffers written: samps were read into VERY START of buf) * no. of samps to write equals samps_read * MINUS those not needed, in samp_offset area..... * (5) After first time, (Buffers laready writ: samps now read into the displaced inbuf) * number of samps to write equals those read * PLUS those already in start of outbuffer, haing been copied back into the write_offset segment. * (6) Do envelope on the incomplete (or exactly full) buffer. * (7) Write this. */ int buf_staggered_envel_processing (int *samps_left_to_process,int samp_offset,int write_offset,double starttime,double *endbrk,double **nextbrk, double *nextgain,int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz) { int exit_status; int samps_to_write_here; int firstime = TRUE; while(*samps_left_to_process > 0) { firstime = FALSE; if((exit_status = do_envelope (dz->buflen,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0) return(exit_status); if((exit_status = write_samps(dz->sampbuf[OUTBUF_START],dz->buflen,dz))<0) return(exit_status); /* 1 */ memmove((char *)dz->sampbuf[OUTBUF_START],(char *)dz->sampbuf[OUTBUF_END],write_offset * sizeof(float)); if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0) return(exit_status); /* 3 */ } if(firstime) samps_to_write_here = dz->ssampsread - samp_offset; /* 4 */ else samps_to_write_here = dz->ssampsread + write_offset; /* 5 */ if((exit_status = do_envelope /* 6 */ (samps_to_write_here,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0) return(exit_status); /* 7 */ if(samps_to_write_here > 0) return write_samps(dz->sampbuf[OUTBUF_START],samps_to_write_here,dz); return(FINISHED); } /**************************** READ_PARTBUF_SAMPS *****************************/ int read_partbuf_samps(int samps_to_read,int *samps_left_to_process, dataptr dz) { if((dz->ssampsread = fgetfbufEx(dz->sampbuf[INBUF_START], samps_to_read,dz->ifd[0],0)) < 0) { sprintf(errstr,"Can't read samples from input soundfile: read_partbuf_samps()\n"); return(SYSTEM_ERROR); } if(dz->ssampsread < samps_to_read) { sprintf(errstr,"Error in buffering arithmetic: read_partbuf_samps()\n"); return(PROGRAM_ERROR); } *samps_left_to_process -= dz->ssampsread; return(FINISHED); } /************************* DO_ENVELOPE ******************************** * * (1) endsampno (absolute numbering) is the final sample to be treated in this call. * * While ever the quit-flag is not set... * (2) if the sample number of the next break-pnt falls before or at the end * of this function call... * Set the 'change' flag, which will cause envelope breakpoints to be * advanced. * (3) set end of the inner-loop pass to this next brkpnt. * (4) If the brkpnt falls exactly at end of pass, set the 'quit' flag. * Otherwise quit remains FALSE, and the outer loop will be recalled (after * breakpoints have been advanced). * (5) Otherwise, the next breakpnt falls beyond the end of this function call. * So don't advance the breakpoints (change = FALSE), sample at end of inner * loop (this_endsamp) is the sample at end of this call-to-function * (endsampno), AND set flag to quit at end of inner loop. * (6) Counter for inner loop is this-endsamp minus current position (sampno). * (7) Inner loop, get gain for each sample, and increment samples accordingly. * (8) Increment the absolute count of processed samples (sampno). * (9) If change flag is set, reset gain and advance breakpoints. * (10) Retain the enveloping gain current at end of buffer. */ int do_envelope (int samp_cnt,double starttime,double *endbrk,double **nextbrk,double *nextgain, int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz) { int exit_status; int n, m, sampcnt; int endsampno, this_endsamp, this_sampcnt; float *obuf = dz->sampbuf[OUTBUF_START]; float *obufend = obuf + dz->buflen; int quit = FALSE, change; double val; double this_gain = *gain; double this_gain_incr = *gain_incr; double this_gain_step = *gain_step; sampcnt = samp_cnt / dz->infile->channels; /* 'stereo'-samples to process */ endsampno = *sampno + sampcnt; /* 1 */ if(sampcnt * dz->infile->channels > dz->buflen) { sprintf(errstr,"Buffering anomaly: do_envelope()\n"); return(PROGRAM_ERROR); } while(quit==FALSE) { if(*nextbrk_sampno <= endsampno) { /* 2 */ change = TRUE; this_endsamp = *nextbrk_sampno; /* 3 */ if(*nextbrk_sampno==endsampno) quit = TRUE; /* 4 */ } else { change = FALSE; /* 5 */ this_endsamp = endsampno; quit = TRUE; } this_sampcnt = this_endsamp - *sampno; /* 6 */ if(obuf + (this_sampcnt * dz->infile->channels) > obufend) { sprintf(errstr,"array overrun: do_envelope()\n"); return(PROGRAM_ERROR); } if(flteq(this_gain,1.0) && flteq(this_gain_step,0.0)) obuf += this_sampcnt * dz->infile->channels; /* no modification of sound */ else { for(n=0;ninfile->channels;m++) { val = /*round*/((double)(*obuf) * this_gain); *obuf = (float)val; obuf++; } } } *sampno += this_sampcnt; /* 8 */ if(change) { /* 9 */ if((exit_status = advance_brkpnts (starttime,gain,endbrk,nextbrk,nextgain,gain_step,gain_incr,nextbrk_sampno,dz))<0) return(exit_status); this_gain = *gain; this_gain_incr = *gain_incr; this_gain_step = *gain_step; } } *gain = this_gain; /* 10 */ return(FINISHED); } /************************* READ_SSAMPS ******************************/ int read_ssamps(int samps_to_read,int *samps_left_to_process,dataptr dz) { if((dz->ssampsread = fgetfbufEx(dz->sampbuf[INBUF_START], samps_to_read,dz->ifd[0],0)) < 0) { sprintf(errstr,"Can't read samples from input soundfile: read_ssamps()\n"); return(SYSTEM_ERROR); } if(dz->ssampsread!=samps_to_read) { sprintf(errstr,"Error in buffering arithmetic: read_ssamps()\n"); return(PROGRAM_ERROR); } *samps_left_to_process -= dz->ssampsread; return(FINISHED); } /******************************** DO_SIMPLE_READ **********************************/ int do_simple_read(int *samps_left_to_process,int bufsize,dataptr dz) { int exit_status; if(*samps_left_to_process < bufsize) exit_status = read_partbuf_samps(*samps_left_to_process,samps_left_to_process,dz); else exit_status = read_ssamps(bufsize,samps_left_to_process,dz); return(exit_status); } /******************************** DO_OFFSET_READ **********************************/ int do_offset_read(int *samps_left_to_process,int samp_offset,int bufsize,dataptr dz) { int exit_status; if(*samps_left_to_process < bufsize) { exit_status = read_partbuf_samps(*samps_left_to_process + samp_offset,samps_left_to_process,dz); *samps_left_to_process = 0; } else { exit_status = read_ssamps(bufsize,samps_left_to_process,dz); *samps_left_to_process += samp_offset; /* some of samps-read are not part of samps-to-process */ } return(exit_status); } /******************************** SKIP_INTO_FILE **********************************/ //RWD ugh! unless this is simply a sndseek to startsamp.... //TW unfortunately, it's intrinsically tied up with old buffering scheme //#ifdef NOTDEF int skip_into_file(int startsamp,int extended_buf_sampsize,int *write_offset,int *samp_offset,dataptr dz) { int skipsamps=(startsamp/extended_buf_sampsize) * extended_buf_sampsize; /* 8 */ int sampsecsize = ENV_FSECSIZE; int sectors_remaining = (startsamp - skipsamps)/sampsecsize; /* 9 */ skipsamps += sectors_remaining * sampsecsize; /* 10 */ *samp_offset = startsamp - skipsamps; /* 11 */ *write_offset = ENV_FSECSIZE - *samp_offset; /* 12 */ if(sndseekEx(dz->ifd[0],skipsamps,0)<0) { /* 13 */ sprintf(errstr,": sndseekEx failed: skip_into_file()\n"); return(SYSTEM_ERROR); } return(FINISHED); } //#endif //TW UPDATE: NEW CODE /*** NEW april 2002 ****/ static int fill_grid_array(double starttime,int *firstpass, double *next_gridstart, double **d, int *arraysize, dataptr dz); static int check_available_space(dataptr dz); static int create_grid_envelope(int n, double *next_gridstart,dataptr dz); static int do_grid_envelope(dataptr dz); static int do_grid_biz(int sib,int eib,int style,int *splicepos,dataptr dz); static void get_nextposition_pair(double *ds,int *startsamp,int *endsamp,int *style,dataptr dz); #define GRID_ZERO (0) #define GRID_COPY (1) #define GRID_DOWN (2) #define GRID_UP (3) /************************************ DO_GRIDS ********************************/ int do_grids(dataptr dz) { int exit_status; int n; int namelen, numlen; char *outfilename; //TW REVISION DEc 2002 // char *outfilenumber; char *p, *q, *r; double next_gridstart; numlen = 4; if(!sloom) { namelen = strlen(dz->wordstor[0]); q = dz->wordstor[0]; r = dz->wordstor[0] + namelen; p = r - 1; while((*p != '\\') && (*p != '/') && (*p != ':')) { p-- ; if(p < dz->wordstor[0]) break; } if(p > dz->wordstor[0]) { p++; while(p <= r) *q++ = *p++; } } namelen = strlen(dz->wordstor[0]); // if(sndunlink(dz->ofd) < 0) { // fprintf(stdout,"WARNING: Can't set initial dummy output soundfile for deletion.\n"); // fflush(stdout); // } // if(sndcloseEx(dz->ofd) < 0) { // fprintf(stdout,"ERROR: Can't close initial dummy output soundfile\n"); // return(SYSTEM_ERROR); // } dz->ofd = -1; if((exit_status = check_available_space(dz))<0) return(exit_status); if((dz->tempsize = dz->insams[0] * dz->iparam[GRID_COUNT])<0) dz->tempsize = INT_MAX; if(sloom) namelen--; /* Drop the 0 at end of name */ next_gridstart = 0.0; if((exit_status = reset_peak_finder(dz))<0) return(exit_status); for(n=0;niparam[GRID_COUNT];n++) { if(sndseekEx(dz->ifd[0],0,0)<0) { sprintf(errstr,"sndseekEx() failed.\n"); return(SYSTEM_ERROR); } reset_filedata_counters(dz); // FEB 2010 TW if((outfilename = (char *)malloc((namelen + numlen + 10) * sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for outfilename.\n"); return(MEMORY_ERROR); } strcpy(outfilename,dz->wordstor[0]); //TW REvision Dec 2002 if(sloom) insert_new_number_at_filename_end(outfilename,n,1); // FEB 2010 TW else { insert_separator_on_sndfile_name(outfilename,1); insert_new_number_at_filename_end(outfilename,n,0); } dz->process_type = EQUAL_SNDFILE; /* allow sndfile to be created */ if((exit_status = create_sized_outfile(outfilename,dz))<0) { if(!sloom) { sprintf(errstr, "Soundfile %s already exists: Made %d grids only.\n",outfilename,n-1); free(outfilename); dz->process_type = OTHER_PROCESS; dz->ofd = -1; return(GOAL_FAILED); } else { dz->process_type = OTHER_PROCESS; dz->ofd = -1; sprintf(errstr, "Soundfile %s already exists: Made %d grids only.\n",outfilename,n-1); return(SYSTEM_ERROR); } } dz->process_type = OTHER_PROCESS; if((exit_status = create_grid_envelope(n,&next_gridstart,dz))<0) return(exit_status); if((exit_status = do_grid_envelope(dz))<0) return(exit_status); dz->process_type = EQUAL_SNDFILE; /* allows header to be written */ dz->outfiletype = SNDFILE_OUT; /* allows header to be written */ if((exit_status = headwrite(dz->ofd,dz))<0) { free(outfilename); return(exit_status); } dz->process_type = OTHER_PROCESS; /* restore true status */ dz->outfiletype = NO_OUTPUTFILE; /* restore true 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); } free(outfilename); dz->ofd = -1; } return(FINISHED); } /************************************ CHECK_AVAILABLE_SPACE ********************************/ #define LEAVESPACE (10*1024) int check_available_space(dataptr dz) { unsigned int slots; unsigned int freespace = getdrivefreespace("temp") - LEAVESPACE; freespace /= sizeof(float); slots = freespace/dz->insams[0]; if(slots < (unsigned int)dz->iparam[COPY_CNT]) { sprintf(errstr,"Insufficient space on disk to create %d copies.\n" "You have space for %d copies.\n",dz->iparam[COPY_CNT],slots); return(GOAL_FAILED); } return(FINISHED); } /************************************ CREATE_GRID_ENVELOPE ********************************/ int create_grid_envelope(int n, double *next_gridstart,dataptr dz) { double *d, time, thistime, grid_step, half_gridsplen; int arraysize = 8, old_arraysize; double starttime; int firstpass, exit_status; if(dz->brksize[GRID_WIDTH] == 0) { grid_step = dz->param[GRID_WIDTH] * dz->iparam[GRID_COUNT]; switch(n) { case(0): if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for grid envelope,\n"); return(MEMORY_ERROR); } d = dz->parray[0]; for(time = 0.0; time <= dz->duration; time += grid_step) { thistime = time; if(flteq(time,0.0)) *d++ = thistime; else { if(dz->brksize[GRID_SPLEN] > 0) read_value_from_brktable(thistime,GRID_SPLEN,dz); half_gridsplen = dz->param[GRID_SPLEN]/2.0; *d++ = thistime + half_gridsplen; } *d++ = 1.0; thistime += dz->param[GRID_WIDTH]; if(dz->brksize[GRID_SPLEN] > 0) read_value_from_brktable(thistime,GRID_SPLEN,dz); half_gridsplen = dz->param[GRID_SPLEN]/2.0; *d++ = thistime - half_gridsplen; *d++ = 1.0; *d++ = thistime + half_gridsplen; *d++ = 0.0; thistime = time + grid_step; if(dz->brksize[GRID_SPLEN] > 0) { read_value_from_brktable(thistime,GRID_SPLEN,dz); } half_gridsplen = dz->param[GRID_SPLEN]/2.0; *d++ = thistime - half_gridsplen; *d++ = 0.0; old_arraysize = arraysize; arraysize += 8; if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for grid envelope,\n"); return(MEMORY_ERROR); } d = dz->parray[0] + old_arraysize; dz->parray[1] = d; /* mark end of parray */ } break; case(1): for(d = dz->parray[1]-2; d >= dz->parray[0];d -= 2) { *(d+4) = (*d) + dz->param[GRID_WIDTH]; /* add time to values, and shift them up two brkpnt places */ *(d+5) = *(d+1); } *(dz->parray[0]) = 0.0; /* Insert a zero time zero val */ *(dz->parray[0]+1) = 0.0; if(dz->brksize[GRID_SPLEN] > 0) { /* And a splice-start zero */ read_value_from_brktable(*(dz->parray[0]+4),GRID_SPLEN,dz); } half_gridsplen = dz->param[GRID_SPLEN]/2.0; *(dz->parray[0]+2) = *(dz->parray[0]+4) - half_gridsplen; *(dz->parray[0]+3) = 0.0; *(dz->parray[0]+4) += half_gridsplen; dz->parray[1] += 4; /* mark end of parray */ break; default: /* move grid by grid-width, except zerotime point */ for(d = dz->parray[1]-2; d >= dz->parray[0]+2;d -= 2) *d += dz->param[GRID_WIDTH]; break; } } else { switch(n) { case(0): starttime = 0.0; firstpass = 1; if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for grid envelope,\n"); return(MEMORY_ERROR); } d = dz->parray[0]; if((exit_status = fill_grid_array(starttime,&firstpass,next_gridstart,&d,&arraysize,dz))<0) return(exit_status); arraysize += 64; /* safety */ if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for grid envelope,\n"); return(MEMORY_ERROR); } break; default: /* move grid by grid-width, except zerotime point */ arraysize = 12; starttime = *next_gridstart; firstpass = 1; d = dz->parray[0] + 4; if((exit_status = fill_grid_array(starttime,&firstpass,next_gridstart,&d,&arraysize,dz))<0) return(exit_status); *(dz->parray[0]) = 0.0; /* Insert a zero time zero val */ *(dz->parray[0]+1) = 0.0; if(dz->brksize[GRID_SPLEN] > 0) /* And a splice-start zero */ read_value_from_brktable(*(dz->parray[0]+4),GRID_SPLEN,dz); half_gridsplen = dz->param[GRID_SPLEN]/2.0; *(dz->parray[0]+2) = *(dz->parray[0]+4) - half_gridsplen; *(dz->parray[0]+3) = 0.0; *(dz->parray[0]+4) += half_gridsplen; break; } } return(FINISHED); } /************************************ FILL_GRID_ARRAY ********************************/ int fill_grid_array(double starttime,int *firstpass, double *next_gridstart, double **d, int *arraysize, dataptr dz) { double grid_step = 0.0, time, thistime, start_gridwidth, this_gridwidth, half_gridsplen = 0.0; int z; int k; //old_arraysize; for(time = starttime; time <=dz->duration; time += grid_step) { grid_step = 0.0; thistime = time; read_value_from_brktable(thistime,GRID_WIDTH,dz); start_gridwidth = dz->param[GRID_WIDTH]; if(*firstpass) /* save initial distance to next grid set */ *next_gridstart += start_gridwidth; this_gridwidth = start_gridwidth; grid_step += this_gridwidth; thistime += this_gridwidth; for(z=1;ziparam[GRID_COUNT];z++) { /*sum steps of all grids to get step from */ read_value_from_brktable(thistime,GRID_WIDTH,dz); /* current window of this grid, to next window of this grid */ this_gridwidth = dz->param[GRID_WIDTH]; grid_step += this_gridwidth; thistime += this_gridwidth; } thistime = time; if(*firstpass) half_gridsplen = 0.0; /* Envelope starts without splice ... splice added in calling routine */ else if(dz->brksize[GRID_SPLEN] > 0) { read_value_from_brktable(thistime,GRID_SPLEN,dz); half_gridsplen = dz->param[GRID_SPLEN]/2.0; } **d = thistime + half_gridsplen; (*d)++; **d = 1.0; (*d)++; thistime += start_gridwidth; if(dz->brksize[GRID_SPLEN] > 0) { read_value_from_brktable(thistime,GRID_SPLEN,dz); half_gridsplen = dz->param[GRID_SPLEN]/2.0; } else if(*firstpass) half_gridsplen = dz->param[GRID_SPLEN]/2.0; /* if no brkpnt table, only need to calc on first pass */ *firstpass = 0; **d = thistime - half_gridsplen; (*d)++; **d = 1.0; (*d)++; **d = thistime + half_gridsplen; (*d)++; **d = 0.0; (*d)++; thistime = time + grid_step; if(dz->brksize[GRID_SPLEN] > 0) { read_value_from_brktable(thistime,GRID_SPLEN,dz); half_gridsplen = dz->param[GRID_SPLEN]/2.0; } **d = thistime - half_gridsplen; (*d)++; **d = 0.0; (*d)++; //old_arraysize = *arraysize; *arraysize += 8; k = *d - dz->parray[0]; if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],(*arraysize) * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for grid envelope,\n"); return(MEMORY_ERROR); } *d = dz->parray[0] + k; dz->parray[1] = *d; /* mark end of parray */ } return(FINISHED); } /************************************ DO_GRID_ENVELOPE ********************************/ int do_grid_envelope(dataptr dz) { double *ds = dz->parray[0]; int sib, eib; /* startpos-ion-buf, edipos-in-buf */ int style, exit_status, finished= 0; int startsamp, endsamp, splicepos = 0,last_total_samps_read = 0; sndseekEx(dz->ifd[0],0,0); get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz); sib = startsamp - last_total_samps_read; eib = endsamp - last_total_samps_read; if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0) return(exit_status); if(dz->ssampsread == 0) { sprintf(errstr,"No data found in input soundfile\n"); return(GOAL_FAILED); } while(ds < dz->parray[1] - 2) { do { while(eib < dz->ssampsread) { do_grid_biz(sib,eib,style,&splicepos,dz); if((ds += 2) >= dz->parray[1] - 2) { finished = 1; break; } get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz); sib = startsamp - last_total_samps_read; eib = endsamp - last_total_samps_read; } if(finished) break; do_grid_biz(sib,dz->ssampsread,style,&splicepos,dz); if(dz->ssampsread > 0) { if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0) return(exit_status); } last_total_samps_read = dz->total_samps_read; if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0) return(exit_status); if(dz->ssampsread == 0) { finished = 1; break; } sib = 0; eib = endsamp - last_total_samps_read; if(eib == 0) { if((ds += 2) >= dz->parray[1] - 2) { finished = 1; break; } get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz); sib = startsamp - last_total_samps_read; eib = endsamp - last_total_samps_read; } } while(!finished); if(finished) break; } if(dz->ssampsread > 0) { if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0) return(exit_status); } return(FINISHED); } /************************************ DO_GRID_BIZ ********************************/ int do_grid_biz(int sib,int eib,int style,int *splicepos,dataptr dz) { double splice_incr, splice_val; int n; switch(style) { case(GRID_ZERO): memset((char *)(dz->sampbuf[0] + sib),0,(eib - sib) * sizeof(float)); break; case(GRID_COPY): break; case(GRID_UP): dz->iparam[GRID_SPLEN] = (int)round(dz->param[GRID_SPLEN] * dz->infile->srate) * dz->infile->channels; splice_incr = 1.0 / (double)dz->iparam[GRID_SPLEN]; splice_val = *splicepos * splice_incr; for(n = sib; n < eib; n++) { dz->sampbuf[0][n] = (float)(dz->sampbuf[0][n] * splice_val); splice_val += splice_incr; (*splicepos)++; } if(*splicepos >= dz->iparam[GRID_SPLEN]) *splicepos = 0; break; case(GRID_DOWN): dz->iparam[GRID_SPLEN] = (int)round(dz->param[GRID_SPLEN] * dz->infile->srate) * dz->infile->channels; splice_incr = 1.0 / (double)dz->iparam[GRID_SPLEN]; splice_val = 1.0 - (*splicepos * splice_incr); for(n = sib; n < eib; n++) { dz->sampbuf[0][n] = (float)(dz->sampbuf[0][n] * splice_val); splice_val -= splice_incr; (*splicepos)++; } if(*splicepos >= dz->iparam[GRID_SPLEN]) *splicepos = 0; break; } return(FINISHED); } /************************************ GET_NEXTPOSITION_PAIR ********************************/ void get_nextposition_pair(double *ds,int *startsamp,int *endsamp,int *style,dataptr dz) { double *de = ds+2, startval, endval; *startsamp = round(*ds * dz->infile->srate) * dz->infile->channels; *endsamp = round(*de * dz->infile->srate) * dz->infile->channels; startval = *(ds+1); endval = *(de+1); if(flteq(startval,1.0)) { if(flteq(endval,1.0)) *style = GRID_COPY; else *style = GRID_DOWN; } else { if(flteq(endval,1.0)) *style = GRID_UP; else *style = GRID_ZERO; } }