216 lines
6.7 KiB
C
216 lines
6.7 KiB
C
|
/* residual.c
|
||
|
* atsa: ATS analysis implementation
|
||
|
* Oscar Pablo Di Liscia / Pete Moss / Juan Pampin
|
||
|
*/
|
||
|
|
||
|
#include "atsa.h"
|
||
|
|
||
|
#include <math.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
/* private function prototypes */
|
||
|
int compute_m(double pha_1, double frq_1, double pha, double frq, int buffer_size);
|
||
|
double compute_aux(double pha_1, double pha, double frq_1, int buffer_size, int M);
|
||
|
double compute_alpha(double aux, double frq_1, double frq, int buffer_size);
|
||
|
double compute_beta(double aux, double frq_1, double frq, int buffer_size);
|
||
|
double interp_phase(double pha_1, double frq_1, double alpha, double beta, int i);
|
||
|
void read_frame(double *fil, int fil_len, int samp_1, int samp_2, double *in_buffer);
|
||
|
void synth_buffer(double a1,double a2, double f1, double f2, double p1, double p2, double *buffer, int frame_samps);
|
||
|
|
||
|
|
||
|
/* Functions for phase interpolation
|
||
|
* All this comes from JOS/XJS article on PARSHL.
|
||
|
* Original phase interpolation eqns. by Qualtieri/McAulay.
|
||
|
*/
|
||
|
|
||
|
int compute_m(double pha_1, double frq_1, double pha, double frq, int buffer_size)
|
||
|
{
|
||
|
int val;
|
||
|
val = (int)((((pha_1 + (frq_1 * (double)buffer_size) - pha) + ((frq - frq_1) * 0.5 * (double)buffer_size)) / TWOPI) + 0.5);
|
||
|
return(val);
|
||
|
}
|
||
|
|
||
|
|
||
|
double compute_aux(double pha_1, double pha, double frq_1, int buffer_size, int M)
|
||
|
{
|
||
|
double val;
|
||
|
val = (double)((pha + (TWOPI * (double)M)) - (pha_1 + (frq_1 * (double)buffer_size)));
|
||
|
return(val);
|
||
|
}
|
||
|
|
||
|
double compute_alpha(double aux, double frq_1, double frq, int buffer_size)
|
||
|
{
|
||
|
double val;
|
||
|
val = (double)(((3.0 / (double)(buffer_size * buffer_size)) * aux ) - ((frq - frq_1) / (double)buffer_size));
|
||
|
return(val);
|
||
|
}
|
||
|
|
||
|
double compute_beta(double aux, double frq_1, double frq, int buffer_size)
|
||
|
{
|
||
|
double val;
|
||
|
val = (double)(((-2.0 / (double)(buffer_size * buffer_size * buffer_size)) * aux) + ((frq - frq_1) / (double)(buffer_size * buffer_size)));
|
||
|
return(val);
|
||
|
}
|
||
|
|
||
|
double interp_phase(double pha_1, double frq_1, double alpha, double beta, int i)
|
||
|
{
|
||
|
double val;
|
||
|
val = (double)((beta * (double)(i * i * i)) + (alpha * (double)(i * i)) + (frq_1 * (double)i) + pha_1);
|
||
|
return(val);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* read_frame
|
||
|
* ==========
|
||
|
* reads a frame from the input file
|
||
|
* fil: pointer to an array with sound data
|
||
|
* fil_len: length of datas in samples
|
||
|
* samp_1: first sample number in frame
|
||
|
* samp_2: last sample number in frame
|
||
|
* in_buffer: pointer to input buffer
|
||
|
* which is filled out by the function
|
||
|
* NOTE: caller should allocate memory for buffer
|
||
|
*/
|
||
|
void read_frame(double *fil, int fil_len, int samp_1, int samp_2, double *in_buffer)
|
||
|
{
|
||
|
int i, samps, index;
|
||
|
double tmp;
|
||
|
samps = samp_2 - samp_1;
|
||
|
for(i = 0 ; i < samps ; i++){
|
||
|
index = samp_1 + i;
|
||
|
if(index < fil_len){
|
||
|
tmp = fil[index];
|
||
|
} else {
|
||
|
tmp = (double)0.0;
|
||
|
}
|
||
|
in_buffer[i] = tmp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* synth_buffer
|
||
|
* ============
|
||
|
* synthesizes a buffer of sound using
|
||
|
* amplitude linear interpolation and
|
||
|
* phase cubic interpolation
|
||
|
* a1: starting amplitude
|
||
|
* a2: ending amplitude
|
||
|
* f1: starting frequency in radians per sample
|
||
|
* f2: ending frequency in radians per sample
|
||
|
* p1: starting phase in radians
|
||
|
* p2: ending phase in radians
|
||
|
* buffer: pointer to synthesis buffer
|
||
|
* which is filled out by the function
|
||
|
* NOTE: caller should allocate memory for buffer
|
||
|
* frame_samps: number of samples in frame (buffer)
|
||
|
*/
|
||
|
void synth_buffer(double a1,double a2, double f1, double f2, double p1, double p2, double *buffer, int frame_samps)
|
||
|
{
|
||
|
int k, M;
|
||
|
double aux, alpha, beta, amp, amp_inc, int_pha;
|
||
|
M = compute_m(p1, f1, p2, f2, frame_samps);
|
||
|
aux = compute_aux(p1, p2, f1, frame_samps, M);
|
||
|
alpha = compute_alpha(aux, f1, f2, frame_samps);
|
||
|
beta = compute_beta(aux, f1, f2, frame_samps);
|
||
|
amp = a1;
|
||
|
amp_inc = (a2 - a1) / (double)frame_samps;
|
||
|
for(k = 0; k < frame_samps; k++){
|
||
|
int_pha = interp_phase(p1, f1, alpha, beta, k);
|
||
|
buffer[k] += amp * cos(int_pha);
|
||
|
amp += amp_inc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* compute_residual
|
||
|
* ================
|
||
|
* Computes the difference between the synthesis and the original sound.
|
||
|
* the <win-samps> array contains the sample numbers in the input file corresponding to each frame
|
||
|
* fil: pointer to analyzed data (1 channel sample array)
|
||
|
* fil_len: length of data in samples
|
||
|
* sound: pointer to ATS_SOUND
|
||
|
* win_samps: pointer to array of analysis windows center times
|
||
|
* file_sampling_rate: sampling rate of analysis file
|
||
|
* res: pointer to output residual data (channel 0 = residual, channel 1 = partials synthesis)
|
||
|
* res_len: pointer to output number of samples in residual data
|
||
|
*/
|
||
|
void compute_residual(double *fil, int fil_len, ATS_SOUND *sound, int *win_samps, int file_sampling_rate, double*** res, int* res_len)
|
||
|
{
|
||
|
int i, frm, frm_1, frm_2, par, frames, partials, frm_samps, out_smp=0;
|
||
|
double *in_buff, *synth_buff, mag, a1, a2, f1, f2, p1, p2, diff, synth;
|
||
|
|
||
|
fprintf(stderr, "Computing residual...\n");
|
||
|
|
||
|
frames = sound->frames;
|
||
|
partials = sound->partials;
|
||
|
frm_samps = sound->frame_size;
|
||
|
mag = TWOPI / (double)file_sampling_rate;
|
||
|
|
||
|
// allocate memory
|
||
|
in_buff = (double *)malloc(frm_samps * sizeof(double));
|
||
|
synth_buff = (double *)malloc(frm_samps * sizeof(double));
|
||
|
|
||
|
*res = (double **)malloc(2*sizeof(double *));
|
||
|
(*res)[0] = (double *)calloc(frm_samps*(frames-1), sizeof(double));
|
||
|
(*res)[1] = (double *)calloc(frm_samps*(frames-1), sizeof(double));
|
||
|
|
||
|
// compute residual frame by frame
|
||
|
for(frm = 1 ; frm < frames ; frm++){
|
||
|
// clean buffers up
|
||
|
for(i = 0; i < frm_samps ; i++){
|
||
|
in_buff[i] = 0.0;
|
||
|
synth_buff[i] = 0.0;
|
||
|
}
|
||
|
frm_1 = frm - 1;
|
||
|
frm_2 = frm;
|
||
|
|
||
|
// read frame from input
|
||
|
read_frame(fil, fil_len, win_samps[frm_1], win_samps[frm_2], in_buff);
|
||
|
|
||
|
// compute one synthesis frame
|
||
|
for(par = 0 ; par < partials; par++){
|
||
|
a1 = sound->amp[par][frm_1];
|
||
|
a2 = sound->amp[par][frm_2];
|
||
|
|
||
|
// have to convert the frequency into radians per sample!!!
|
||
|
f1 = sound->frq[par][frm_1];
|
||
|
f2 = sound->frq[par][frm_2];
|
||
|
f1 *= mag;
|
||
|
f2 *= mag;
|
||
|
p1 = sound->pha[par][frm_1];
|
||
|
p2 = sound->pha[par][frm_2];
|
||
|
if( !( a1 <= 0.0 && a2 <= 0.0 ) ) {
|
||
|
|
||
|
// check amp 0 in frame 1
|
||
|
if( a1 <= 0.0 ){
|
||
|
f1 = f2;
|
||
|
p1 = p2 - ( f2 * frm_samps );
|
||
|
while(p1 > PI){ p1 -= TWOPI; }
|
||
|
while(p1 < (PI * -1)){ p1 += TWOPI; }
|
||
|
}
|
||
|
|
||
|
// check amp 0 in frame 2
|
||
|
if( a2 <= 0.0 ){
|
||
|
f2 = f1;
|
||
|
p2 = p1 + ( f1 * frm_samps );
|
||
|
while(p2 > PI){ p2 -= TWOPI; }
|
||
|
while(p2 < (PI * -1)){ p2 += TWOPI; }
|
||
|
}
|
||
|
synth_buffer(a1, a2, f1, f2, p1, p2, synth_buff, frm_samps);
|
||
|
}
|
||
|
}
|
||
|
// write output: chan 0 = residual, chan 1 = synthesis
|
||
|
for(i = 0 ; i < frm_samps ; i++){
|
||
|
synth = synth_buff[i];
|
||
|
diff = in_buff[i] - synth;
|
||
|
(*res)[0][out_smp] = diff;
|
||
|
(*res)[1][out_smp] = synth;
|
||
|
out_smp++;
|
||
|
}
|
||
|
}
|
||
|
free(in_buff);
|
||
|
free(synth_buff);
|
||
|
*res_len = out_smp;
|
||
|
}
|