213 lines
5.6 KiB
C
213 lines
5.6 KiB
C
/* atsa.c
|
|
* atsa: ATS analysis implementation
|
|
* Oscar Pablo Di Liscia / Pete Moss / Juan Pampin
|
|
* Adaptations for libsndfile sound IO by jpmeuret@free.fr
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <sndfile.h>
|
|
|
|
#include "atsa.h"
|
|
|
|
|
|
static int load_samples(char* filename, double*** samples, off_t* frames,
|
|
int* channels, int* s_rate);
|
|
static int save_sound(ATS_SOUND* sound, char* filename, double SMR_thres, int type);
|
|
static int save_residual(double** residual, int frames, int s_rate);
|
|
|
|
|
|
/* main_anal
|
|
* =========
|
|
* main analysis function
|
|
* soundfile: path to input file
|
|
* out_file: path to output ats file
|
|
* anargs: pointer to analysis parameters
|
|
* returns error status
|
|
*/
|
|
int main_anal(char *soundfile, char *ats_outfile, ANARGS *anargs)
|
|
{
|
|
int chan;
|
|
off_t frames;
|
|
int channels;
|
|
int s_rate;
|
|
double** samples = 0;
|
|
double** residual = 0;
|
|
int res_frames;
|
|
ATS_SOUND* sound = 0;
|
|
|
|
if (!load_samples(soundfile, &samples, &frames, &channels, &s_rate))
|
|
{
|
|
if ((sound = tracker(anargs, samples[0], s_rate, frames, &residual, &res_frames)))
|
|
{
|
|
if (!save_sound(sound, ats_outfile, anargs->SMR_thres, anargs->type))
|
|
{
|
|
if (save_residual(residual, res_frames, s_rate))
|
|
{
|
|
fprintf(stderr, "Could not save residual");
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Could not save ATS sound");
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Partials analysis failed");
|
|
return 1;
|
|
}
|
|
|
|
if (residual)
|
|
{
|
|
for (chan = 0; chan < 2; chan++)
|
|
if (residual[chan])
|
|
free(residual[chan]);
|
|
free(residual);
|
|
}
|
|
|
|
/* free ATS_SOUND memory */
|
|
free_sound(sound);
|
|
|
|
/* finally sound */
|
|
free(sound);
|
|
}
|
|
|
|
if (samples)
|
|
{
|
|
for (chan = 0; chan < channels; chan++)
|
|
if (samples[chan])
|
|
free(samples[chan]);
|
|
free(samples);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* This will be the length of the buffer used to hold samples while
|
|
** we process them.
|
|
*/
|
|
#define BUFFER_LEN 1024
|
|
|
|
static int load_samples(char* filename, double*** samples, off_t* frames,
|
|
int* channels, int* s_rate)
|
|
{
|
|
/* This is a buffer of double precision floating point values
|
|
** which will hold our data while we process it.
|
|
*/
|
|
static double data[BUFFER_LEN] ;
|
|
|
|
/* A SNDFILE is very much like a FILE in the Standard C library. The
|
|
** sf_open_read and sf_open_write functions return an SNDFILE* pointer
|
|
** when they sucessfully open the specified file.
|
|
*/
|
|
SNDFILE* infile;
|
|
|
|
/* A pointer to an SF_INFO stutct is passed to sf_open_read and sf_open_write
|
|
** which fill this struct with information about the file.
|
|
*/
|
|
SF_INFO sfinfo ;
|
|
|
|
/* Here's where we open the input file. We pass sf_open_read the file name and
|
|
** a pointer to an SF_INFO struct.
|
|
** On successful open, sf_open_read returns a SNDFILE* pointer which is used
|
|
** for all subsequent operations on that file.
|
|
** If an error occurs during sf_open_read, the function returns a NULL pointer.
|
|
*/
|
|
if (! (infile = sf_open(filename, SFM_READ, &sfinfo)))
|
|
{ /* Open failed so print an error message. */
|
|
printf ("Not able to open input file %s.\n", filename) ;
|
|
/* Print the error message fron libsndfile. */
|
|
sf_perror (NULL) ;
|
|
return 1 ;
|
|
} ;
|
|
|
|
/* warn about multi-channel sound files */
|
|
if (sfinfo.channels > 1)
|
|
{
|
|
fprintf(stderr, "Error: file has %d channels, must be mono!\n", sfinfo.channels);
|
|
return 1;
|
|
}
|
|
|
|
/* Allocate the sound arrays */
|
|
int chan;
|
|
*samples = (double**)malloc(sfinfo.channels * sizeof(double*));
|
|
for (chan = 0; chan < sfinfo.channels; chan++)
|
|
*samples[chan] = (double*)malloc(sfinfo.frames * sizeof(double));
|
|
|
|
|
|
/* While there are samples in the input file, read them */
|
|
sf_count_t fram, frame_count;
|
|
int samp;
|
|
while ((frame_count = sf_readf_double (infile, data, BUFFER_LEN)))
|
|
{
|
|
samp = 0;
|
|
for (fram = 0; fram < frame_count; fram++)
|
|
for (chan = 0; chan < sfinfo.channels; chan++)
|
|
*samples[chan][fram] = data[samp++];
|
|
}
|
|
|
|
/* Close input file. */
|
|
sf_close (infile);
|
|
|
|
*frames = sfinfo.frames;
|
|
*channels = sfinfo.channels;
|
|
*s_rate = sfinfo.samplerate;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
static int save_sound(ATS_SOUND* sound, char* filename, double SMR_thres, int type)
|
|
{
|
|
if(!sound)
|
|
return(-2);
|
|
|
|
fprintf(stderr,"done!\n");
|
|
fprintf(stderr,"saving sound...\n");
|
|
ats_save(sound, filename, SMR_thres, type);
|
|
fprintf(stderr, "done!\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int save_residual(double** residual, int frames, int s_rate)
|
|
{
|
|
static char* filename = "residual.wav";
|
|
|
|
/* A SNDFILE is very much like a FILE in the Standard C library. The
|
|
** sf_open_read and sf_open_write functions return an SNDFILE* pointer
|
|
** when they sucessfully open the specified file.
|
|
*/
|
|
SNDFILE* outfile;
|
|
|
|
/* A pointer to an SF_INFO struct is passed to sf_open_read and sf_open_write
|
|
** which fill this struct with information about the file.
|
|
*/
|
|
SF_INFO sfinfo ;
|
|
sfinfo.samplerate = s_rate;
|
|
sfinfo.channels = 2;
|
|
sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
|
|
|
|
/* Open the output file. */
|
|
if (! (outfile = sf_open(filename, SFM_WRITE, &sfinfo)))
|
|
{ printf ("Not able to open output file %s.\n", filename) ;
|
|
sf_perror (NULL) ;
|
|
return 1 ;
|
|
}
|
|
|
|
/* While there are residual samples, write them to the output file */
|
|
sf_count_t fram;
|
|
int chan;
|
|
for (fram = 0; fram < frames; fram++)
|
|
for (chan = 0; chan < sfinfo.channels; chan++)
|
|
sf_write_double (outfile, &residual[chan][fram], 1) ;
|
|
|
|
/* Close output file. */
|
|
sf_close (outfile);
|
|
|
|
return 0;
|
|
}
|