#include "../include/tscope.h"
#include "../include/tscope/internal.h"
static int playCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *usersample)
{
snd2_sample *samp = (snd2_sample *) usersample;
float *sampledata = &samp->data[samp->current_frame * samp->channels];
float *bufferdata = (float *) outputBuffer;
unsigned int i;
int finished;
unsigned int framesLeft = samp->frames - samp->current_frame;
(void) inputBuffer;
(void) timeInfo;
(void) statusFlags;
(void) usersample;
if (framesLeft < framesPerBuffer) {
for (i = 0; i < framesLeft; i++) {
*(bufferdata++) = *(sampledata++);
if (samp->channels == 2)
*(bufferdata++) = *(sampledata++);
}
for (; i < framesPerBuffer; i++) {
*(bufferdata++) = 0;
if (samp->channels == 2)
*(bufferdata++) = 0;
}
samp->current_frame += framesLeft;
finished = paComplete;
}
else {
for (i = 0; i < framesPerBuffer; i++) {
*(bufferdata++) = *(sampledata++);
if (samp->channels == 2)
*(bufferdata++) = *(sampledata++);
}
samp->current_frame += framesPerBuffer;
finished = paContinue;
}
return finished;
}
static int recordCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo * timeInfo,
PaStreamCallbackFlags statusFlags,
void *usersample)
{
snd2_sample *samp = (snd2_sample *) usersample;
const float *bufferdata = (const float *) inputBuffer;
float *wptr = &samp->data[samp->current_frame * samp->channels];
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = samp->frames - samp->current_frame;
(void) outputBuffer;
(void) timeInfo;
(void) statusFlags;
(void) usersample;
if (framesLeft < framesPerBuffer) {
framesToCalc = framesLeft;
finished = paComplete;
}
else {
framesToCalc = framesPerBuffer;
finished = paContinue;
}
if (inputBuffer == NULL) {
for (i = 0; i < framesToCalc; i++) {
*wptr++ = 0;
if (samp->channels == 2)
*wptr++ = 0;
}
}
else {
for (i = 0; i < framesToCalc; i++) {
*wptr++ = *bufferdata++;
if (samp->channels == 2)
*wptr++ = *bufferdata++;
}
}
samp->current_frame += framesToCalc;
return finished;
}
snd2_stream *snd2_playsample(snd2_sample *samp)
{
samp->current_frame=0;
if (!_snd2_flag)
_snd2_init();
PaStreamParameters outparam;
outparam.device = Pa_GetDefaultOutputDevice();
if (outparam.device==paNoDevice)
ts_fatal("snd2_playsample: no output device found\n");
outparam.channelCount = samp->channels;
outparam.sampleFormat = paFloat32;
outparam.suggestedLatency = Pa_GetDeviceInfo(outparam.device)->defaultLowOutputLatency;
if (_debug_flag > DEBUG1)
fprintf(stderr, "suggested output latency: %f\n", outparam.suggestedLatency);
outparam.hostApiSpecificStreamInfo = NULL;
snd2_stream *stream;
int err;
err =
Pa_OpenStream(&stream, NULL, &outparam, samp->samplerate,
FRAMES_PER_BUFFER, paClipOff, playCallback, samp);
if(err)
ts_fatal(Pa_GetErrorText( err ));
if (stream) {
err = Pa_StartStream(stream);
if(err)
ts_fatal(Pa_GetErrorText( err ));
}
return stream;
}
snd2_stream * snd2_recordsample(snd2_sample *samp)
{
samp->current_frame=0;
if (!_snd2_flag)
_snd2_init();
PaStreamParameters inparam;
inparam.device = Pa_GetDefaultInputDevice();
if (inparam.device==paNoDevice)
ts_fatal ("snd2_recordsample: no input device found\n");
inparam.channelCount = samp->channels;
inparam.sampleFormat = paFloat32;
inparam.suggestedLatency =
Pa_GetDeviceInfo(inparam.device)->defaultLowInputLatency;
if (_debug_flag > DEBUG1)
fprintf(stderr, "suggested input latency: %f\n", inparam.suggestedLatency);
inparam.hostApiSpecificStreamInfo = NULL;
snd2_stream *stream;
int err;
err =
Pa_OpenStream(&stream, &inparam, NULL, samp->samplerate,
FRAMES_PER_BUFFER, paClipOff, recordCallback, samp);
if(err)
ts_fatal(Pa_GetErrorText( err ));
err = Pa_StartStream(stream);
if(err)
ts_fatal(Pa_GetErrorText( err ));
return stream;
}
int snd2_querysample(snd2_stream * stream)
{
int err;
err = Pa_IsStreamActive(stream);
if (err < 0)
ts_fatal(Pa_GetErrorText( err ));
return err;
}
void snd2_stopsample(snd2_stream * stream)
{
int err;
err = Pa_CloseStream(stream);
if(err)
ts_fatal(Pa_GetErrorText( err ));
}
float snd2_getstreamtime(snd2_stream * stream)
{
return (Pa_GetStreamTime(stream));
}
__int64 snd2_getsampletime(snd2_sample * samp)
{
return (_snd2_filebufferlength + samp->current_frame * samp->channels);
}
void snd2_recordsample_blocking(snd2_sample *samp)
{
if (!_snd2_flag)
_snd2_init();
PaStreamParameters inparam;
inparam.device = Pa_GetDefaultInputDevice();
if (inparam.device==paNoDevice)
ts_fatal ("snd2_recordsample_blocking: no input device found\n");
inparam.channelCount = samp->channels;
inparam.sampleFormat = paFloat32;
inparam.suggestedLatency = Pa_GetDeviceInfo( inparam.device )->defaultLowInputLatency;
if (_debug_flag > DEBUG1)
fprintf(stderr, "snd2_recordsample_blocking: suggested input latency: %f\n", inparam.suggestedLatency);
inparam.hostApiSpecificStreamInfo = NULL;
snd2_stream *stream;
int err;
err = Pa_OpenStream(&stream, &inparam, NULL, samp->samplerate, FRAMES_PER_BUFFER, \
paClipOff, NULL, NULL );
if(err)
ts_fatal(Pa_GetErrorText( err ));
err = Pa_StartStream( stream );
if(err)
ts_fatal(Pa_GetErrorText( err ));
err = Pa_ReadStream( stream, samp->data, samp->frames );
if(err)
ts_fatal(Pa_GetErrorText( err ));
err = Pa_CloseStream( stream );
if(err)
ts_fatal(Pa_GetErrorText( err ));
}
void snd2_playsample_blocking(snd2_sample *samp)
{
if (!_snd2_flag)
_snd2_init();
PaStreamParameters outparam;
outparam.device = Pa_GetDefaultOutputDevice();
if (outparam.device==paNoDevice)
ts_fatal ("snd2_playsample_blocking: no output device found\n");
outparam.channelCount = samp->channels;
outparam.sampleFormat = paFloat32;
outparam.suggestedLatency = Pa_GetDeviceInfo( outparam.device )->defaultLowOutputLatency;
if (_debug_flag > DEBUG1)
fprintf(stderr, "snd2_playsample_blocking: suggested output latency: %f\n", outparam.suggestedLatency);
outparam.hostApiSpecificStreamInfo = NULL;
snd2_stream *stream;
int err;
err = Pa_OpenStream (&stream, NULL, &outparam, samp->samplerate, FRAMES_PER_BUFFER, \
paClipOff, NULL, NULL);
if(err)
ts_fatal(Pa_GetErrorText( err ));
if (stream) {
err = Pa_StartStream( stream );
if(err)
ts_fatal(Pa_GetErrorText( err ));
err = Pa_WriteStream(stream, samp->data, samp->frames);
if(err)
ts_fatal(Pa_GetErrorText( err ));
err = Pa_CloseStream( stream );
if(err)
ts_fatal(Pa_GetErrorText( err ));
}
}
void snd2_tobuffer(snd2_sample * samp)
{
FILE *fp;
fp = fopen ("buff.raw", "a+");
if (!fp)
ts_fatal ("snd2_tobuffer: could not open buffer file\n");
sf_count_t start=samp->current_frame;
fwrite(samp->data, sizeof(float), start * samp->channels, fp);
sf_count_t stop=samp->current_frame;
fclose(fp);
samp->current_frame=stop-start;
int i, updated=stop-start;
for (i=0; i<updated; i++)
samp->data[i] = samp->data[i+start];
_snd2_filebufferlength += (start * samp->channels);
}
void snd2_frombuffer(snd2_sample *samp)
{
FILE *fp;
fp = fopen ("buff.raw", "r");
if (!fp)
ts_fatal ("snd2_frombuffer: could not open dump file\n");
sf_count_t l=0;
float tmp;
int ret;
while((ret=fread(&tmp, sizeof(float), 1, fp)))
l++;
rewind(fp);
samp=snd2_makesample(0);
samp->current_frame=0;
samp->samplerate=_snd2_samplerate;
samp->channels=_snd2_channels;
samp->frames=l;
snd2_allocatesample(samp);
ret=fread(samp->data, sizeof(float), l, fp);
if (l!=ret)
ts_fatal ("snd2_frombuffer: could not read all samples\n");
fclose(fp);
}
snd2_sample * snd2_readsample (char *file)
{
SF_INFO sfinfo ;
SNDFILE *infile;
if (! (infile = sf_open (file, SFM_READ, &sfinfo)))
ts_fatal("snd2_readsample: could not open %s\n", file);
if (! sf_format_check (&sfinfo)) {
sf_close (infile) ;
ts_fatal("snd2_readsample: %s is not in WAV format\n", file) ;
}
if ( !(sfinfo.format & SF_FORMAT_WAV) ) {
sf_close (infile) ;
ts_fatal("snd2_readsample: %s is not in WAV format\n", file) ;
}
if (sfinfo.samplerate != 11025 && sfinfo.samplerate != 22050 && sfinfo.samplerate != 44100) {
sf_close (infile) ;
ts_fatal("snd2_readsample: %s's samplerate is not 11025, 22050 or 44100\n", file) ;
}
if (sfinfo.channels!=1 && sfinfo.channels!=2) {
sf_close (infile) ;
ts_fatal("snd2_readsample: %s is not mono or stereo\n", file) ;
}
snd2_sample *samp;
samp=snd2_makesample(0);
samp->samplerate=sfinfo.samplerate;
samp->channels=sfinfo.channels;
samp->frames=sfinfo.frames;
snd2_allocatesample(samp);
sf_count_t readcount;
readcount = sf_readf_float(infile, samp->data, sfinfo.frames);
if (readcount != samp->frames) {
sf_close (infile) ;
ts_fatal("snd2_readsample: could not read all frames in %s\n", file) ;
}
sf_close(infile);
return samp;
}
int snd2_writesample(snd2_sample *samp, char *file)
{
SF_INFO sfinfo ;
sfinfo.frames = samp->frames;
sfinfo.samplerate = samp->samplerate;
sfinfo.channels = samp->channels;
if (_snd2_sampleformat == SAMPLE_INTEGER)
sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
else if (_snd2_sampleformat == SAMPLE_FLOAT)
sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
else
ts_fatal("snd2_writesample has bugs\n", file) ;
sfinfo.sections = 1;
sfinfo.seekable =1;
SNDFILE *outfile;
if (! (outfile = sf_open (file, SFM_WRITE, &sfinfo)))
ts_fatal("write sample: could not open %s\n", file) ;
sf_count_t writecount;
writecount = sf_writef_float(outfile, samp->data, samp->frames);
if (writecount != samp->frames) {
sf_close (outfile) ;
ts_fatal("snd2_writesample: could not write all frames in %s\n", file) ;
}
sf_close(outfile);
return writecount;
}
snd2_sample *snd2_makesample(sf_count_t length)
{
if (length<0)
ts_fatal("snd2_makesample: length should be positive\n");
snd2_sample *samp=(snd2_sample *)malloc(sizeof(snd2_sample));
if (samp==NULL)
ts_fatal ("snd2_makesample: could not allocate sample\n");
samp->current_frame=0;
samp->samplerate=_snd2_samplerate;
samp->channels=_snd2_channels;
samp->frames=(_snd2_samplerate*length)/1000;
if (length>0)
snd2_allocatesample(samp);
return samp;
}
void snd2_allocatesample(snd2_sample *samp)
{
samp->data=(float *)malloc(samp->frames*samp->channels*sizeof(float));
memset(samp->data, 0, samp->frames*samp->channels*sizeof(float));
if (samp->data==NULL)
ts_fatal ("snd2_allocatesample: could not allocate memory\n") ;
}
void snd2_killsample (snd2_sample *samp)
{
if (samp && samp->data)
free (samp->data);
if (samp)
free(samp);
}
int snd2_channels(int channels)
{
int oldchannels=_snd2_channels;
if (channels != MONO && channels !=STEREO)
ts_fatal ("snd2_channels: only mono (1) or stereo (2) samples are supported\n");
_snd2_channels=channels;
return oldchannels;
}
int snd2_samplerate(int rate)
{
int oldrate=_snd2_samplerate;
if (rate != 11025 && rate != 22050 && rate != 44100)
ts_fatal ("snd2_samplerate: 11025, 22050 and 44100 Hz are the only supported samplerates\n");
_snd2_samplerate=rate;
return oldrate;
}
int snd2_sampleformat(int format)
{
int oldformat=_snd2_sampleformat;
if (format != SAMPLE_INTEGER && format != SAMPLE_FLOAT)
ts_fatal ("snd2_sampleformat: sample format %l undefined\n", format);
_snd2_sampleformat=format;
return oldformat;
}