mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-26 22:28:41 -05:00
3731d5a0c3
2. "/A" added to list of optional callsign suffixes. 3. Improved algorithm for measuring error in soundcard sample rates. 4. Optional 5-sec shift of input data, to catch some clock errors. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/trunk@274 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
374 lines
9.6 KiB
C
374 lines
9.6 KiB
C
#include <stdio.h>
|
|
#include <portaudio.h>
|
|
#include <string.h>
|
|
|
|
void fivehz_();
|
|
void fivehztx_();
|
|
void addnoise_(short int *n);
|
|
|
|
// Definition of structure pointing to the audio data
|
|
typedef struct
|
|
{
|
|
double *Tsec;
|
|
double *tbuf;
|
|
int *iwrite;
|
|
int *ibuf;
|
|
int *TxOK;
|
|
int *ndebug;
|
|
int *ndsec;
|
|
int *Transmitting;
|
|
int *nwave;
|
|
int *nmode;
|
|
int *trperiod;
|
|
int nbuflen;
|
|
int nfs;
|
|
short *y1;
|
|
short *y2;
|
|
short *iwave;
|
|
}
|
|
paTestData;
|
|
|
|
typedef struct _SYSTEMTIME
|
|
{
|
|
short Year;
|
|
short Month;
|
|
short DayOfWeek;
|
|
short Day;
|
|
short Hour;
|
|
short Minute;
|
|
short Second;
|
|
short Millisecond;
|
|
} SYSTEMTIME;
|
|
|
|
#ifdef Win32
|
|
extern void __stdcall GetSystemTime(SYSTEMTIME *st);
|
|
#else
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
|
|
void GetSystemTime(SYSTEMTIME *st){
|
|
struct timeval tmptimeofday;
|
|
struct tm tmptmtime;
|
|
gettimeofday(&tmptimeofday,NULL);
|
|
gmtime_r(&tmptimeofday.tv_sec,&tmptmtime);
|
|
st->Year = (short)tmptmtime.tm_year;
|
|
st->Month = (short)tmptmtime.tm_year;
|
|
st->DayOfWeek = (short)tmptmtime.tm_wday;
|
|
st->Day = (short)tmptmtime.tm_mday;
|
|
st->Hour = (short)tmptmtime.tm_hour;
|
|
st->Minute = (short)tmptmtime.tm_min;
|
|
st->Second = (short)tmptmtime.tm_sec;
|
|
st->Millisecond = (short)(tmptimeofday.tv_usec/1000);
|
|
}
|
|
#endif
|
|
|
|
// Input callback routine:
|
|
static int SoundIn( void *inputBuffer, void *outputBuffer,
|
|
unsigned long framesPerBuffer,
|
|
const PaStreamCallbackTimeInfo* timeInfo,
|
|
PaStreamCallbackFlags statusFlags,
|
|
void *userData )
|
|
{
|
|
paTestData *data = (paTestData*)userData;
|
|
short *in = (short*)inputBuffer;
|
|
unsigned int i;
|
|
static int n0;
|
|
static int ia=0;
|
|
static int ib=0;
|
|
static int ic=0;
|
|
static int TxOKz=0;
|
|
static int ncall=0;
|
|
static int nsec0=0;
|
|
static double stime0=86400.0;
|
|
int nsec;
|
|
double stime;
|
|
SYSTEMTIME st;
|
|
|
|
// Get System time
|
|
GetSystemTime(&st);
|
|
nsec = (int) (st.Hour*3600.0 + st.Minute*60.0 + st.Second);
|
|
stime = nsec + st.Millisecond*0.001 + *data->ndsec*0.1;
|
|
*data->Tsec = stime;
|
|
nsec=(int)stime;
|
|
ncall++;
|
|
|
|
// NB: inputBufferAdcTime and currentTime do not work properly.
|
|
/*
|
|
if(nsec!=nsec0) {
|
|
printf("%f %f %f %f\n",stime,timeInfo->inputBufferAdcTime,
|
|
timeInfo->currentTime,timeInfo->outputBufferDacTime);
|
|
}
|
|
*/
|
|
|
|
// if((inputBuffer==NULL) & (ncall>2) & (stime>stime0)) {
|
|
if((statusFlags!=0) & (ncall>2) & (stime>stime0)) {
|
|
if(*data->ndebug)
|
|
printf("Status flags %d at Tsec = %7.1f s, DT = %7.1f\n",
|
|
statusFlags,stime,stime-stime0);
|
|
stime0=stime;
|
|
}
|
|
|
|
if((statusFlags&1)==0) {
|
|
//increment buffer pointers only if data available
|
|
ia=*data->iwrite;
|
|
ib=*data->ibuf;
|
|
ib++; //Increment ibuf
|
|
if(ib>1024) ib=1;
|
|
*data->ibuf=ib;
|
|
data->tbuf[ib-1]=stime;
|
|
for(i=0; i<framesPerBuffer; i++) {
|
|
data->y1[ia] = (*in++);
|
|
data->y2[ia] = (*in++);
|
|
ia++;
|
|
}
|
|
}
|
|
|
|
if(ia >= data->nbuflen) ia=0; //Wrap buffer pointer if necessary
|
|
*data->iwrite = ia; //Save buffer pointer
|
|
fivehz_(); //Call fortran routine
|
|
nsec0=nsec;
|
|
return 0;
|
|
}
|
|
|
|
// Output callback routine:
|
|
static int SoundOut( void *inputBuffer, void *outputBuffer,
|
|
unsigned long framesPerBuffer,
|
|
const PaStreamCallbackTimeInfo* timeInfo,
|
|
PaStreamCallbackFlags statusFlags,
|
|
void *userData )
|
|
{
|
|
paTestData *data = (paTestData*)userData;
|
|
short *wptr = (short*)outputBuffer;
|
|
unsigned int i,n;
|
|
static short int n2;
|
|
static int n0;
|
|
static int ia=0;
|
|
static int ib=0;
|
|
static int ic=0;
|
|
static int TxOKz=0;
|
|
static double stime0=86400.0;
|
|
int nsec;
|
|
double stime;
|
|
SYSTEMTIME st;
|
|
|
|
// Get System time
|
|
GetSystemTime(&st);
|
|
nsec = (int) (st.Hour*3600.0 + st.Minute*60.0 + st.Second);
|
|
stime = nsec + st.Millisecond*0.001 + *data->ndsec*0.1;
|
|
*data->Tsec = stime;
|
|
nsec=(int)stime;
|
|
|
|
if(*data->TxOK && (!TxOKz)) {
|
|
n=nsec/(*data->trperiod);
|
|
// ic = (int)(stime - *data->trperiod*n) * data->nfs/framesPerBuffer;
|
|
// ic = framesPerBuffer*ic;
|
|
ic = (int)(stime - *data->trperiod*n) * data->nfs;
|
|
ic = ic % *data->nwave;
|
|
}
|
|
|
|
TxOKz=*data->TxOK;
|
|
*data->Transmitting=*data->TxOK;
|
|
|
|
if(*data->TxOK) {
|
|
for(i=0 ; i<framesPerBuffer; i++ ) {
|
|
n2=data->iwave[ic];
|
|
addnoise_(&n2);
|
|
*wptr++ = n2; //left
|
|
*wptr++ = n2; //right
|
|
ic++;
|
|
if(ic>=*data->nwave) {
|
|
if(*data->nmode==2) {
|
|
*data->TxOK=0;
|
|
ic--;
|
|
}
|
|
else
|
|
ic = ic % *data->nwave; //Wrap buffer pointer if necessary
|
|
}
|
|
}
|
|
} else {
|
|
memset((void*)outputBuffer, 0, 2*sizeof(short)*framesPerBuffer);
|
|
}
|
|
fivehztx_(); //Call fortran routine
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************/
|
|
int jtaudio_(int *ndevin, int *ndevout, short y1[], short y2[],
|
|
int *nbuflen, int *iwrite, short iwave[],
|
|
int *nwave, int *nfsample, int *nsamperbuf,
|
|
int *TRPeriod, int *TxOK, int *ndebug,
|
|
int *Transmitting, double *Tsec, int *ngo, int *nmode,
|
|
double tbuf[], int *ibuf, int *ndsec)
|
|
{
|
|
paTestData data;
|
|
PaStream *instream;
|
|
PaStream *outstream;
|
|
PaStreamParameters inputParameters;
|
|
PaStreamParameters outputParameters;
|
|
// PaStreamInfo *streamInfo;
|
|
|
|
int nfs,ndin,ndout;
|
|
PaError err1,err2,err2a,err3,err3a;
|
|
double dnfs;
|
|
|
|
data.Tsec = Tsec;
|
|
data.tbuf = tbuf;
|
|
data.iwrite = iwrite;
|
|
data.ibuf = ibuf;
|
|
data.TxOK = TxOK;
|
|
data.ndebug = ndebug;
|
|
data.ndsec = ndsec;
|
|
data.Transmitting = Transmitting;
|
|
data.y1 = y1;
|
|
data.y2 = y2;
|
|
data.nbuflen = *nbuflen;
|
|
data.nmode = nmode;
|
|
data.nwave = nwave;
|
|
data.iwave = iwave;
|
|
data.nfs = *nfsample;
|
|
data.trperiod = TRPeriod;
|
|
|
|
nfs=*nfsample;
|
|
err1=Pa_Initialize(); // Initialize PortAudio
|
|
if(err1) {
|
|
printf("Error initializing PortAudio.\n");
|
|
printf("%s\n",Pa_GetErrorText(err1));
|
|
goto error;
|
|
}
|
|
|
|
ndin=*ndevin;
|
|
ndout=*ndevout;
|
|
dnfs=(double)nfs;
|
|
printf("Opening device %d for input, %d for output.\n",ndin,ndout);
|
|
|
|
inputParameters.device=*ndevin;
|
|
inputParameters.channelCount=2;
|
|
inputParameters.sampleFormat=paInt16;
|
|
inputParameters.suggestedLatency=1.0;
|
|
inputParameters.hostApiSpecificStreamInfo=NULL;
|
|
err2=Pa_OpenStream(
|
|
&instream, //address of stream
|
|
&inputParameters,
|
|
NULL,
|
|
dnfs, //Sample rate
|
|
2048, //Frames per buffer
|
|
paNoFlag,
|
|
SoundIn, //Callback routine
|
|
&data); //address of data structure
|
|
if(err2) {
|
|
printf("Error opening Audio stream for input.\n");
|
|
printf("%s\n",Pa_GetErrorText(err2));
|
|
goto error;
|
|
}
|
|
|
|
outputParameters.device=*ndevout;
|
|
outputParameters.channelCount=2;
|
|
outputParameters.sampleFormat=paInt16;
|
|
outputParameters.suggestedLatency=1.0;
|
|
outputParameters.hostApiSpecificStreamInfo=NULL;
|
|
err2a=Pa_OpenStream(
|
|
&outstream, //address of stream
|
|
NULL,
|
|
&outputParameters,
|
|
dnfs, //Sample rate
|
|
2048, //Frames per buffer
|
|
paNoFlag,
|
|
SoundOut, //Callback routine
|
|
&data); //address of data structure
|
|
if(err2a) {
|
|
printf("Error opening Audio stream for output.\n");
|
|
printf("%s\n",Pa_GetErrorText(err2a));
|
|
goto error;
|
|
}
|
|
|
|
err3=Pa_StartStream(instream); //Start input stream
|
|
if(err3) {
|
|
printf("Error starting input Audio stream\n");
|
|
printf("%s\n",Pa_GetErrorText(err3));
|
|
goto error;
|
|
}
|
|
err3a=Pa_StartStream(outstream); //Start output stream
|
|
if(err3a) {
|
|
printf("Error starting output Audio stream\n");
|
|
printf("%s\n",Pa_GetErrorText(err3a));
|
|
goto error;
|
|
}
|
|
|
|
printf("Audio streams running normally.\n******************************************************************\n");
|
|
|
|
while(Pa_IsStreamActive(instream)) {
|
|
if(*ngo==0) goto StopStream;
|
|
// printf("CPU: %f\n",Pa_GetStreamCpuLoad(stream));
|
|
Pa_Sleep(200);
|
|
}
|
|
|
|
StopStream:
|
|
Pa_AbortStream(instream); // Abort stream
|
|
Pa_CloseStream(instream); // Close stream, we're done.
|
|
Pa_AbortStream(outstream); // Abort stream
|
|
Pa_CloseStream(outstream); // Close stream, we're done.
|
|
Pa_Terminate();
|
|
return(0);
|
|
|
|
error:
|
|
printf("%d %d %f %d %d %d %d %d\n",ndin,ndout,dnfs,err1,
|
|
err2,err2a,err3,err3a);
|
|
Pa_Terminate();
|
|
return(1);
|
|
}
|
|
|
|
|
|
int padevsub_(int *numdev, int *ndefin, int *ndefout,
|
|
int nchin[], int nchout[])
|
|
{
|
|
int i;
|
|
int numDevices;
|
|
const PaDeviceInfo *pdi;
|
|
PaError err;
|
|
// PaHostApiInfo *hostapi;
|
|
|
|
Pa_Initialize();
|
|
|
|
/*
|
|
n=Pa_GetHostApiCount();
|
|
printf("HostAPI Type #Devices \n");
|
|
for(i=0; i<n; i++) {
|
|
hostapi=Pa_GetHostApiInfo(i);
|
|
printf(" %3d %2d %3d %s\n",i,hostapi->type,
|
|
hostapi->deviceCount,hostapi->name);
|
|
}
|
|
*/
|
|
|
|
// numDevices = Pa_CountDevices();
|
|
numDevices = Pa_GetDeviceCount();
|
|
*numdev=numDevices;
|
|
if( numDevices < 0 ) {
|
|
err = numDevices;
|
|
goto error;
|
|
}
|
|
|
|
|
|
printf("\nAudio Input Output Device Name\n");
|
|
printf("Device Channels Channels\n");
|
|
printf("------------------------------------------------------------------\n");
|
|
|
|
for( i=0; i<numDevices; i++ ) {
|
|
pdi = Pa_GetDeviceInfo( i );
|
|
// if(i == Pa_GetDefaultInputDeviceID()) *ndefin=i;
|
|
// if(i == Pa_GetDefaultOutputDeviceID()) *ndefout=i;
|
|
if(i == Pa_GetDefaultInputDevice()) *ndefin=i;
|
|
if(i == Pa_GetDefaultOutputDevice()) *ndefout=i;
|
|
nchin[i]=pdi->maxInputChannels;
|
|
nchout[i]=pdi->maxOutputChannels;
|
|
printf(" %2d %2d %2d %s\n",i,nchin[i],nchout[i],pdi->name);
|
|
}
|
|
|
|
Pa_Terminate();
|
|
return 0;
|
|
|
|
error:
|
|
Pa_Terminate();
|
|
return err;
|
|
}
|
|
|