572 lines
18 KiB
C
572 lines
18 KiB
C
/*
|
|
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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
#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; i<ats_sound->frames - 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; i<ats_sound->frames; ++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; z<ats_sound->partials; ++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; z<ATSA_CRITICAL_BANDS; ++z) {
|
|
res_band_centers[z]= res_band_edges[z]+((res_band_edges[z+1]-res_band_edges[z])*0.5);
|
|
randi_setup(sparams->sr,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; z<ats_sound->partials; ++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;
|
|
}
|
|
|