soundeditor/atsa/synthesis.atsh.c

572 lines
18 KiB
C
Raw Permalink Normal View History

/*
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;
}