/* SYNTHESIS.C Oscar Pablo Di Liscia / Juan Pampin Extracted from atsh synth-funcs.c, with slight modifications (by jpmeuret@free.fr) : - change from random() to rand() random number generator (gcc 4 compatibility) - do_synthesis no longer writes to a sound file, but simply allocates and returns a sample array => now independant from any sound IO library. */ #include #include #include #include "atsa.h" //CONSTANTS #define TWO_PI (2*3.141592653589793) #define TABLE_LENGTH 16384 #define SYNTH_RES 1 #define SYNTH_DET 2 #define SYNTH_BOTH 3 //MACROS /* ;;; In these macros pha_1 and frq_1 refers to the instantaneous phase ;;; and frequency of the previous frame while pha and frq refer ;;; to the phase and frequency of the present frame. */ #define COMPUTE_M(pha_1, frq_1, pha, frq, dt) ((pha_1 + (frq_1 * dt) - pha) + ((frq - frq_1) * .5 * dt)) / TWO_PI #define COMPUTE_AUX(pha_1, pha, frq_1, dt, M) (pha + (TWO_PI * M)) - (pha_1 + (frq_1 * dt)) #define COMPUTE_ALPHA(aux, frq_1, frq, dt) ((3. / (dt * dt)) * aux ) - ((frq - frq_1) / dt) #define COMPUTE_BETA(aux, frq_1, frq, dt) ((-2. / (dt * dt * dt)) * aux) + ((frq - frq_1) / (dt * dt)) /* ;;; note that for this macro the values of i should go ;;; from 0 to dt. So in the case of having 220 samples ;;; within a frame the increment for i will be dt/200 */ #define INTERP_PHASE(pha_1, frq_1, alpha, beta, i) (beta * i * i * i) + (alpha * i * i)+ (frq_1 * i) + pha_1 #define ENG_RMS(val, ws) sqrt((double)val/(ws * (double)ATSA_NOISE_VARIANCE)) //STRUCTURES typedef struct { //the time data for each time breakpoint of the time function int from; //from frame int to; //to frame int size; //the size of the segment in frames double tfac; //stretching factor 1=invariant } TIME_DATA; typedef struct { //the data for the randi UG int size; //size of the frame in samples this should be sr/freq. double a1; //first amplitude value double a2; //next amplitude value int cnt; //sample position counter } RANDI; //GLOBAL VARIABLES static double *sine_table = 0; /////////////////////////////////////////////////////////////////// //randi output random numbers in the range of 1,-1 //getting a new number at frequency freq and interpolating //the intermediate values. static void randi_setup(double sr, double freq, RANDI *radat) { radat->size= (int) (sr / freq) - 1; radat->a1 = rand(); radat->a2 = rand(); radat->cnt = 0; } /////////////////////////////////////////////////////////////////// static double randi(RANDI *radat) { double output; if(radat->cnt == radat->size) { //get a new random value radat->a1 = radat->a2; radat->a2 = rand(); radat->cnt = 0; } output=(double)(((radat->a2 - radat->a1)/ radat->size) * radat->cnt)+ radat->a1; radat->cnt++; return(1. - ((double)(output /(long int)RAND_MAX) * 2.)); } /////////////////////////////////////////////////////////////////// static double randif(RANDI *radat, double freq, double sr) { double output; if(radat->cnt == radat->size) { //get a new random value radat->a1 = radat->a2; radat->a2 = rand(); radat->cnt = 0; radat->size= (int) (sr / freq) - 1; } output=(double)(((radat->a2 - radat->a1)/ radat->size) * radat->cnt)+ radat->a1; radat->cnt++; return(1. - ((double)(output /(long int)RAND_MAX) * 2.)); } /////////////////////////////////////////////////////////////////// static void make_sine_table() { int i; double theta=0.; double incr = TWO_PI / (double)TABLE_LENGTH; sine_table= (double*) malloc(TABLE_LENGTH * sizeof(double)); for(i=0; i < TABLE_LENGTH; i++) { sine_table[i] = sin(theta); theta +=incr; } return; } //////////////////////////////////////////////////////////////////// static double ioscilator(double amp,double frec,int op, double sr, double *oscpt) { double output; double incr = frec * (double)TABLE_LENGTH / sr; int v2=0; if (!sine_table) make_sine_table(); //LINEAR INTERPOLATION //v2=((int)(oscpt[op] + 1.)) % TABLE_LENGTH; v2=(int)(oscpt[op] + 1.); while ( v2 >= TABLE_LENGTH ) v2 -=TABLE_LENGTH; output=amp * (sine_table[(int)oscpt[op]] + ((sine_table[(int)v2] - sine_table[(int)oscpt[op]]) * ( oscpt[op] - (int)oscpt[op] ))); // oscpt[op] = remainder(oscpt[op] + incr, (double)TABLE_LENGTH); oscpt[op] += incr; while ( oscpt[op] >= (double)TABLE_LENGTH ) oscpt[op] -=(double)TABLE_LENGTH; while ( oscpt[op] < 0. ) oscpt[op] +=(double)TABLE_LENGTH; return output; } /////////////////////////////////////////////////////////////// static double locate_frame(ATS_SOUND *ats_sound, double from_frame, double time, double dif) { //Assuming that the duration of each frame may be different, we //do not have any other method to locate the frame for a given time int i=(int)floor(from_frame), frame=0; //These two cases are obvious if(time <= ats_sound->time[0][1]){ return 0; } if(time >= ats_sound->time[0][ats_sound->frames-1]){ return ats_sound->frames - 1; } //not obvious cases... if(dif >= 0.) do { if(ats_sound->time[0][i] >= time) { frame = i; break; } ++i; } while(i < ats_sound->frames); else do { if(ats_sound->time[0][i] <= time) { frame = i; break; } --i; } while(i > 0); if(frame < 0) frame = 0; else if(frame > ats_sound->frames-1) frame = ats_sound->frames - 1; return frame; } //////////////////////////////////////////////////////////////////// //Synthesizes a Buffer using phase interpolation (not used for the moment) /* static void synth_buffer_phint(double a1, double a2, double f1, double f2, double p1, double p2, double dt, double frame_samps, double* frbuf) { double t_inc, a_inc, M, aux, alpha, beta, time, amp, scale, new_phase; int k, index; double out=0., phase=0.; if (!sine_table) make_sine_table(); f1 *=TWO_PI; f2 *=TWO_PI; t_inc= dt / frame_samps; a_inc= (a2 - a1) / frame_samps; M = COMPUTE_M(p1, f1, p2, f2,dt); aux = COMPUTE_AUX(p1, p2, f1, dt, M); alpha= COMPUTE_ALPHA(aux,f1,f2,dt); beta = COMPUTE_BETA(aux,f1,f2,dt); time = 0.; amp = a1; scale = TWO_PI / ((double)TABLE_LENGTH - 1.); //must take it out from here... for(k = 0; k < (int)frame_samps; k++) { phase = INTERP_PHASE(p1,f1,alpha,beta,time); new_phase = (phase >= TWO_PI ? phase - TWO_PI : phase); index=(int)((new_phase / TWO_PI)*(double)TABLE_LENGTH - 1.); while ( index >= TABLE_LENGTH ) { index -=TABLE_LENGTH; } while ( index < 0 ) { index +=TABLE_LENGTH; } out = sine_table[index] * amp; ///////////////////////////////////////////////////////// time +=t_inc; amp +=a_inc; frbuf[k] +=out; //buffer adds each partial at each pass } return; } */ //////////////////////////////////////////////////////////////////// //Synthesizes a Buffer NOT using phase interpolation static void synth_deterministic_only(double a1, double a2, double f1, double f2, double frame_samps, int op, double *oscpt, SPARAMS* sparams, int *selected, double* frbuf) { int k; double a_inc, f_inc, amp, frec; amp = a1; frec = f1; a_inc= (a2 - a1) / frame_samps; f_inc= (f2 - f1) / frame_samps; if(a1==0. && a2==0.) return; //no synthesis if no amplitude //we should do this conditional on the main loop... if (!sparams->allorsel || !selected || selected[op]) { for(k = 0; k < frame_samps; k++) { //buffer adds each partial at each pass frbuf[k] += ioscilator(amp,frec,op,sparams->sr,oscpt) * sparams->amp; amp +=a_inc; frec +=f_inc; } } return; } //////////////////////////////////////////////////////////////////// static void synth_residual_only(double a1, double a2,double freq,double frame_samps,int op,double *oscpt, RANDI* rdata, SPARAMS* sparams, double* frbuf) { int k; double a_inc, amp; amp = a1; a_inc= (a2 - a1) / frame_samps; if(a1==0. && a2==0.) return; //no synthesis if no amplitude for(k = 0; k < (int)frame_samps; k++) { frbuf[k] += ioscilator(amp,freq,op,sparams->sr,oscpt) * sparams->ramp * randi(rdata); amp += a_inc; } return; } //////////////////////////////////////////////////////////////////// static void synth_both(double a1, double a2, double f1, double f2, double frame_samps,int op, double *oscpt,double r1, double r2, RANDI* rdata, SPARAMS* sparams, int *selected, double* frbuf) { int k; double a_inc, f_inc, amp, frec; double r_inc, res; double out=0., rsig; double rf1, rf2, rf_inc, rfreq; rf1 =(f1< 500.? 50. : f1 * .05); rf2 =(f2< 500.? 50. : f2 * .05); rf_inc=(rf2 - rf1) / frame_samps; rfreq = rf1; amp = a1; frec = f1; res = r1; a_inc = (a2 - a1) / frame_samps; f_inc = (f2 - f1) / frame_samps; r_inc = (r2 - r1) / frame_samps; if(a1==0. && a2==0.) return; //no synthesis if no amplitude //we should do this conditional on the main loop... if (!sparams->allorsel || !selected || selected[op]) { for(k = 0; k < (int)frame_samps; k++) { out = ioscilator(1.0,frec,op,sparams->sr,oscpt); rsig = res*randif(rdata,rfreq,sparams->sr); frbuf[k] += out * (amp * sparams->amp + rsig * sparams->ramp); amp += a_inc; frec += f_inc; res += r_inc; rfreq += rf_inc; } } return; } static double compute_max_frame_dur(ATS_SOUND *ats_sound) { int i; double dt,maxtim=0.; for(i=0; iframes - 1; ++i) { dt=ats_sound->time[0][1+i] - ats_sound->time[0][i]; if(dt > maxtim) maxtim=dt; //find out max. dt. } return maxtim; } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// /////////THIS IS THE MAIN SYNTHESIS LOOP//////////////////////////// //////////////////////////////////////////////////////////////////// void do_atsh_synthesis(ATS_SOUND *ats_sound, SPARAMS* sparams, CURVE* timenv, int *selected, double** out_samps, int* n_out_samps) { int i,x,z,j,maxlen, curr, next, sflag; double dt=0., rfreq; double frame_samps, bw=.1; int bframe, eframe; double dur, dy, cxval, cyval, nxval, nyval, difx, dify; TIME_DATA *tdata; int nbp; double *dospt=0, *rospt=0; RANDI *rarray=0; double* res_band_edges=ATSA_CRITICAL_BAND_EDGES; double res_band_centers[ATSA_CRITICAL_BANDS]; double maxtim, todo; double* frbuf; int n_samps; //double done=0; //fix special params values if (sparams->end <= sparams->beg) sparams->end = ats_sound->dur - sparams->beg; //do residual data transfer if noise data is present if (ats_sound->band_energy) { for(i=0; iframes; ++i) { band_energy_to_res(ats_sound, i); } } //NOW CHECK WHAT TO DO... if(sparams->ramp == 0.) { //deterministic synthesis only sflag=SYNTH_DET; } else { if(sparams->amp == 0.) { //residual synthesis only sflag=SYNTH_RES; } else { //residual and deterministic synthesis sflag=SYNTH_BOTH; } } //precompute some useful data. nbp = get_nbp(timenv); dur = sparams->end - sparams->beg; dy = get_maxy_value(timenv) - get_miny_value(timenv); tdata = (TIME_DATA*)malloc(nbp * sizeof(TIME_DATA)); sparams->max_stretch=0.; todo=0; //We first must calculate data of each control point bframe = 0; for(i=0; i < nbp - 1; ++i){ //get the data from the time envelope and convert it to time cxval= dur * get_x_value(timenv, i); // We assume xmin=0, xmax=1 cyval= dur * get_y_value(timenv, i) * dy; // We assume ymin=0 nxval= dur * get_x_value(timenv, i+1); // We assume xmin=0, xmax=1 nyval= dur * get_y_value(timenv, i+1) * dy; // We assume ymin=0 //diff=0. is a special case we must take in account //here all we do is to set it to one millisecond (arbitrarly) difx= nxval - cxval; if(difx == 0.) difx=.001; dify= nyval - cyval; if(dify == 0.) dify=.001; //find out the max. stretching factor(needed to allocate the I/O buffer) if(fabs(difx) / fabs(dify) >= sparams->max_stretch) { sparams->max_stretch=fabs(difx) / fabs(dify); } //locate the frame for the begining and end of segments if(i == 0){ if(dify < 0.) bframe = (int)locate_frame(ats_sound, ats_sound->frames, cyval, dify); else { bframe = (int)locate_frame(ats_sound, 0, cyval, dify); } } eframe= (int)locate_frame(ats_sound, bframe, nyval, dify); //collect the data to be used tdata[i].from= bframe; tdata[i].to = eframe; tdata[i].size= (int)fabs(eframe - bframe) + 1; tdata[i].tfac= fabs(difx/dify); // update the number of samples to synthesise if (eframe >= ats_sound->frames - 1) dt=fabs(ats_sound->dur - ats_sound->time[0][bframe]); else dt=fabs(ats_sound->time[0][eframe+1] - ats_sound->time[0][bframe]); todo+=dt * sparams->sr * tdata[i].tfac; fprintf(stderr, "do_synthesis(atsh): seg %d : from=%d, to=%d, size=%d, tfac=%f, dt=%f\n", i, tdata[i].from, tdata[i].to, tdata[i].size, tdata[i].tfac, dt); bframe=eframe; } //ALLOCATE OUTPUT SAMPLE ARRAY *out_samps = (double*)malloc((int)todo*sizeof(double)); fprintf(stderr, "do_synthesis(atsh): %d samples to be generated\n", (int)todo); //ALLOCATE AND CLEAN AUDIO BUFFER maxtim = compute_max_frame_dur(ats_sound); maxlen= (int)ceil(maxtim * sparams->sr * sparams->max_stretch); frbuf = (double *) malloc(maxlen * sizeof(double)); for(z = 0; z < maxlen; ++z) { frbuf[z]=0.; } switch(sflag) { //see which memory resources do we need and allocate them case SYNTH_DET: { dospt = (double *) malloc(ats_sound->partials * sizeof(double)); for(z=0; zpartials; ++z) { dospt[z]=0.; } break; } case SYNTH_RES: { rospt = (double *) malloc(ATSA_CRITICAL_BANDS * sizeof(double)); rarray= (RANDI *) malloc(ATSA_CRITICAL_BANDS * sizeof(RANDI)); for(z=0; zsr,res_band_edges[z+1]-res_band_edges[z],&rarray[z]); rospt[z]=0.; } break; } case SYNTH_BOTH: { dospt = (double *) malloc(ats_sound->partials * sizeof(double)); rarray= (RANDI *) malloc(ats_sound->partials * sizeof(RANDI)); for(z=0; zpartials; ++z) { rfreq=bw * (ats_sound->frq[z][(int)floorf(tdata[0].from)] < 500. ? 500. : ats_sound->frq[z][(int)floorf(tdata[0].from)]); randi_setup(sparams->sr,rfreq,&rarray[z]); dospt[z]=0.; } break; } } //NOW DO IT... n_samps=0; for(i = 0; i < nbp - 1; i++) { curr=tdata[i].from; for(j=0; j < tdata[i].size; j++) { next= tdata[i].from < tdata[i].to ? curr+1 : curr-1 ; if(next < 0 || next >= ats_sound->frames) break; dt=fabs(ats_sound->time[0][next] - ats_sound->time[0][curr]); frame_samps=dt * sparams->sr * tdata[i].tfac ; //done += frame_samps; //fprintf(stderr, "do_synthesis: i=%d, curr=%d, next=%d, dt=%g, samps=%f (%f/%f)\n", // i, curr, next, dt, frame_samps, done, todo); switch (sflag) { case SYNTH_DET: { //deterministic synthesis only for(x = 0; x < ats_sound->partials; x++) { synth_deterministic_only(ats_sound->amp[x][curr], ats_sound->amp[x][next], ats_sound->frq[x][curr] * sparams->frec, ats_sound->frq[x][next] * sparams->frec, frame_samps,x, dospt, sparams, selected, frbuf); } break; } case SYNTH_RES: { //residual synthesis only for(x = 0; x < ATSA_CRITICAL_BANDS; x++) { synth_residual_only(ENG_RMS(ats_sound->band_energy[x][curr], ats_sound->window_size), ENG_RMS(ats_sound->band_energy[x][next], ats_sound->window_size) , res_band_centers[x],frame_samps,x,rospt, &rarray[x],sparams, frbuf); } break; } case SYNTH_BOTH: { //residual and deterministic synthesis for(x = 0; x < ats_sound->partials; x++) { synth_both(ats_sound->amp[x][curr], ats_sound->amp[x][next], ats_sound->frq[x][curr] * sparams->frec, ats_sound->frq[x][next] * sparams->frec, frame_samps,x, dospt, ENG_RMS(ats_sound->res[x][curr] * sparams->ramp, ats_sound->window_size), ENG_RMS(ats_sound->res[x][next] * sparams->ramp, ats_sound->window_size), &rarray[x], sparams, selected, frbuf); } break; } }//end switch for(z=0; z< maxlen; ++z) { //copy output buffer to out_samps and clean it if(z < (int)frame_samps) { (*out_samps)[n_samps++] = (double)frbuf[z]; } frbuf[z]=0.; } curr= next; fprintf(stderr, " frame#%d, samps=%f (%d/%f)\n", j, frame_samps, n_samps, todo); } } //CHANGE CONTROL POINT *n_out_samps = n_samps; fprintf(stderr, "do_synthesis(atsh): %d samples generated\n", *n_out_samps); free(frbuf); if (dospt) free(dospt); if (rospt) free(rospt); if (rarray) free(rarray); free(tdata); return; }