/* * 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 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int do_specpinfo(dataptr dz); static int specpzeros(dataptr dz); static int prescale_transposition_data(dataptr dz); static int generate_noise_in_buffer(double noischan_amp,dataptr dz); static int generate_tone_in_buffer(double pre_totalamp,double thisfrq,dataptr dz); static int preset_chanfrqs_to_chancentres(dataptr dz); static int construct_screen_message(dataptr dz); /**************************** SPECPINFO *********************/ int specpinfo(dataptr dz) { int exit_status, valid_pitch_data = FALSE; int n; if(dz->is_transpos) { if((dz->transpos = (float *)malloc(dz->wlength * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for transposition array.\n"); return(MEMORY_ERROR); } for(n=0;nwlength;n++) dz->transpos[n] = 1.0f; /* DEFAULT: no transposition */ } for(n=0;nwlength;n++) { if(dz->pitches[n] > FLTERR) { valid_pitch_data = 1; break; } } if(!valid_pitch_data) { sprintf(errstr,"No valid pitches found in input data.\n"); return(DATA_ERROR); } switch(dz->process) { case(P_INFO): if((exit_status = do_specpinfo(dz))<0) return(exit_status); break; case(P_ZEROS): if((exit_status = specpzeros(dz))<0) return(exit_status); break; default: sprintf(errstr,"Unknown process in specpinfo()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /************************************* DO_SPECPINFO ******************************/ int do_specpinfo(dataptr dz) { int exit_status; int n, minpos = -1, maxpos = -1; for(n=0;nwlength;n++) { if(dz->pitches[n]pitches[n] > dz->param[PINF_MAX]) { dz->param[PINF_MAX] = dz->pitches[n]; maxpos = n; } if(dz->pitches[n] < dz->param[PINF_MIN]) { dz->param[PINF_MIN] = dz->pitches[n]; minpos = n; } dz->param[PINF_MEAN] += dz->pitches[n]; } dz->param[PINF_MEAN] /= (double)dz->wlength; dz->param[PINF_MAXPOS] = (double)maxpos * dz->frametime; dz->param[PINF_MINPOS] = (double)minpos * dz->frametime; if(maxpos < 0) { sprintf(errstr,"No valid pitch information found.\n"); return(GOAL_FAILED); } if(minpos < 0) { sprintf(errstr,"No valid pitch below the nyquist frq found.\n"); return(GOAL_FAILED); } if((exit_status = construct_screen_message(dz))<0) return(exit_status); return(FINISHED); } /***************************** SPECPZEROS *****************/ int specpzeros(dataptr dz) { int n; dz->zeroset = FALSE; for(n=0;nwlength;n++) { if(dz->pitches[n]zeroset = TRUE; break; } } if(dz->zeroset) sprintf(errstr,"File contains unpitched windows.\n"); else sprintf(errstr,"File does NOT contain unpitched windows.\n"); return(FINISHED); } /*************************************** SPECPSEE *************************/ int specpsee(dataptr dz) { int exit_status; int wc; double val; if(dz->is_transpos) { if((exit_status = prescale_transposition_data(dz))<0) return(exit_status); for(wc=0;wcwlength;wc++) { *(dz->sbufptr[0]++) = dz->transpos[wc]; if(dz->sbufptr[0] >= dz->sampbuf[1]) { if((exit_status = write_exact_samps(dz->bigbuf,dz->buflen,dz))<0) return(exit_status); dz->sbufptr[0] = dz->bigbuf; } } } else { for(wc=0;wcwlength;wc++) { if((val = dz->pitches[wc] * dz->param[PSEE_SCF]) > F_MAXSAMP) { if(!dz->zeroset) { fprintf(stdout,"WARNING: output value(s) too big: truncated.\n"); dz->zeroset = TRUE; } val = F_MAXSAMP; } if(val < F_MINSAMP) { if(!dz->zeroset) { fprintf(stdout,"WARNING: output value(s) too small: truncated.\n"); dz->zeroset = TRUE; } val = F_MINSAMP; } *(dz->sbufptr[0]++) = (float)val; if(dz->sbufptr[0] >= dz->sampbuf[1]) { if((exit_status = write_exact_samps(dz->bigbuf,dz->buflen,dz))<0) return(exit_status); dz->sbufptr[0] = dz->bigbuf; } } } if(dz->sbufptr[0] != dz->bigbuf) { if((exit_status = write_samps(dz->bigbuf,dz->sbufptr[0] - dz->bigbuf,dz))<0) return(exit_status); } return(FINISHED); } /*************************** PRESCALE_TRANSPOSITION_DATA ********************/ int prescale_transposition_data(dataptr dz) { int n; double scalefact; double mintransp = DBL_MAX; double maxtransp = -DBL_MAX; for(n=0;nwlength;n++) { if(dz->transpos[n] <= 0.0) { sprintf(errstr,"Anomaly in transposition data: prescale_transposition_data()\n"); return(PROGRAM_ERROR); } dz->transpos[n] = (float)log10(dz->transpos[n]); if(dz->transpos[n] < mintransp) mintransp = dz->transpos[n]; if(dz->transpos[n] > maxtransp) maxtransp = dz->transpos[n]; } maxtransp = max(fabs(maxtransp),fabs(mintransp)); scalefact = F_MAXSAMP/2.0/maxtransp; for(n=0;nwlength;n++) dz->transpos[n] = (float)(dz->transpos[n] * scalefact); return(FINISHED); } /************************* SPECPHEAR *************************/ int specphear(dataptr dz) { #define WINDOW_AMP (0.50) /* AVOID OVERLOAD */ int exit_status; double pre_totalamp, noischan_amp; double thisfrq; int n = 0; int vc; pre_totalamp = WINDOW_AMP * dz->param[PH_GAIN]; noischan_amp = pre_totalamp/(double)dz->clength; memset((char *)dz->bigfbuf,0,(size_t)(dz->big_fsize * sizeof(float))); dz->flbufptr[0] = dz->bigfbuf; dz->infile->channels = dz->infile->origchans; /* setup channel count for outfile */ dz->wanted = dz->infile->channels; while(n < dz->wlength) { thisfrq = (double)dz->pitches[n]; if(thisfrq < 0.0) { /* NO PITCH FOUND : GENERATE NOISE */ if((exit_status = generate_noise_in_buffer(noischan_amp,dz))<0) return(exit_status); } else { /* GENERATE TESTTONE AT FOUND PITCH */ if((exit_status = preset_chanfrqs_to_chancentres(dz))<0) return(exit_status); if((exit_status = generate_tone_in_buffer(pre_totalamp,thisfrq,dz))<0) return(exit_status); } if(n==0) { for(vc = 0; vc < dz->wanted ; vc += 2) dz->flbufptr[0][AMPP] = 0.0f; } if((dz->flbufptr[0] += dz->wanted) >= dz->flbufptr[1]) { if((exit_status = write_exact_samps(dz->bigfbuf,dz->big_fsize,dz))<0) return(exit_status); memset((char *)dz->bigfbuf,0,(size_t)(dz->big_fsize * sizeof(float))); dz->flbufptr[0] = dz->bigfbuf; } n++; } if(dz->flbufptr[0] != dz->bigfbuf) { if((exit_status = write_samps(dz->bigfbuf,dz->flbufptr[0] - dz->bigfbuf,dz))<0) return(exit_status); } return(FINISHED); } /*************************** GENERATE_NOISE_IN_BUFFER *********************/ int generate_noise_in_buffer(double noischan_amp,dataptr dz) { int cc, vc; dz->flbufptr[0][0] = (float)noischan_amp; dz->flbufptr[0][1] = (float)(drand48() * dz->halfchwidth); for(cc = 1, vc = 2; cc < dz->clength-1; cc++, vc += 2) { dz->flbufptr[0][FREQ] = (float)((drand48() * dz->chwidth) + dz->windowbuf[CHBOT][cc]); dz->flbufptr[0][AMPP] = (float)noischan_amp; } dz->flbufptr[0][FREQ] = (float)((drand48() * dz->halfchwidth) + dz->windowbuf[CHBOT][cc]); dz->flbufptr[0][AMPP] = (float)noischan_amp; return(FINISHED); } /********************** GENERATE_TONE_IN_BUFFER ***************************/ int generate_tone_in_buffer(double pre_totalamp,double thisfrq,dataptr dz) { int exit_status; int cc, vc, m, ampadjusted = 0; int lastvc = -1; double post_totalamp; for(m=0;mhalfchwidth)/dz->chwidth); /* TRUNCATE */ vc = cc * 2; if(vc != lastvc) { /* AVOID OVERWRITING ALREADY GENERATED LOWER PARTIALS */ dz->flbufptr[0][AMPP] = dz->windowbuf[TESTPAMP][m]; dz->flbufptr[0][FREQ] = (float)thisfrq; } lastvc = vc; if((thisfrq = thisfrq * 2.0) > dz->nyquist) { post_totalamp = (double)dz->windowbuf[TOTPAMP][m]; /* THIS NORMALISATION DOESN'T QUITE WORK */ if((exit_status = normalise(pre_totalamp,post_totalamp,dz))<0) return(exit_status); ampadjusted = 1; /* IF PITCH IS LESS THAN CHAN SPACING */ break; /* BUT THAT'S MINOR AESTHETIC QUIBBLE ONLY */ } } if(!ampadjusted) { post_totalamp = (double)dz->windowbuf[TOTPAMP][PARTIALS_IN_TEST_TONE-1]; if((exit_status = normalise(pre_totalamp,post_totalamp,dz))<0) return(exit_status); } return(FINISHED); } /**************************** PRESET_CHANFRQS_TO_CHANCENTRES ********************** * * Preset all frqs to centre of channels. */ int preset_chanfrqs_to_chancentres(dataptr dz) { int cc, vc; dz->flbufptr[0][1] = (float)(dz->halfchwidth/2.0); for(cc = 1, vc = 2; cc < dz->clength-1; cc++, vc += 2) dz->flbufptr[0][FREQ] = (float)(dz->windowbuf[CHBOT][cc] + dz->halfchwidth); dz->flbufptr[0][FREQ]=(float)(dz->windowbuf[CHBOT][dz->clength-1]+(dz->halfchwidth/2.0)); return(FINISHED); } /****************************** SPECPWRITE *********************************/ int specpwrite(dataptr dz) { int exit_status; int brkcnt; if((dz->parray[PW_BRK] = (double *)malloc(dz->wlength * 2 * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for pitch brkpnt array.\n"); return(MEMORY_ERROR); } if(dz->is_transpos) { if((exit_status = convert_pch_or_transpos_data_to_brkpnttable(&brkcnt,dz->transpos,dz->frametime,PW_BRK,dz))<0) return(exit_status); } else { if((exit_status = convert_pch_or_transpos_data_to_brkpnttable(&brkcnt,dz->pitches,dz->frametime,PW_BRK,dz))<0) return(exit_status); } return write_brkfile(dz->fp,brkcnt,PW_BRK,dz); } /****************************** CONSTRUCT_SCREEN_MESSAGE *********************************/ int construct_screen_message(dataptr dz) { int exit_status; int oct = 0; double z1, z2, z3, z4, z5; if((exit_status = hztomidi(&z1,dz->param[PINF_MAX]))<0) return(exit_status); if((exit_status = hztomidi(&z2,dz->param[PINF_MIN]))<0) return(exit_status); if((exit_status = hztomidi(&z3,dz->param[PINF_MEAN]))<0) return(exit_status); if((exit_status = hztomidi(&z4,dz->param[PINF_MAX]))<0) return(exit_status); if((exit_status = hztomidi(&z5,dz->param[PINF_MIN]))<0) return(exit_status); z4 -= z5; if(z4 > 12.0) { oct = (int)(z4/12.0); /* TRUNCATE */ z4 -= (double)(oct * 12); } if(oct > 0) { sprintf(errstr,"MAX PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n" "MIN PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n" "MEAN PITCH: %.2lfHZ\tMIDI : %.2lf\n\n" "TOTAL RANGE: %d OCTAVES and %.2lf SEMITONES\n", dz->param[PINF_MAX],z1,dz->param[PINF_MAXPOS],dz->param[PINF_MIN],z2,dz->param[PINF_MINPOS], dz->param[PINF_MEAN],z3, oct, z4); } else { sprintf(errstr,"MAX PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n" "MIN PITCH : %.2lfHZ\tMIDI : %.2lf\tTIME %.2lf\n" "MEAN PITCH: %.2lfHZ\tMIDI : %.2lf\n\n" "TOTAL RANGE: %.2lf SEMITONES\n", dz->param[PINF_MAX],z1,dz->param[PINF_MAXPOS],dz->param[PINF_MIN],z2,dz->param[PINF_MINPOS], dz->param[PINF_MEAN],z3,z4); } return(FINISHED); }