mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-08-27 16:46:36 -04:00
- SNR displayed on decode line - Separate transmit() subroutine - Output sent to all_ft2.txt - Display Rx level (hit L to toggle On/Off) - Auto-sequencing (hit A to toggle On/Off)
348 lines
9.7 KiB
C
348 lines
9.7 KiB
C
#include <stdio.h>
|
|
#include "portaudio.h"
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
int iaa;
|
|
int icc;
|
|
double total_time=0.0;
|
|
|
|
// Definition of structure pointing to the audio data
|
|
typedef struct
|
|
{
|
|
int *iwrite;
|
|
int *itx;
|
|
int *TxOK;
|
|
int *Transmitting;
|
|
int *nwave;
|
|
int *nright;
|
|
int nring;
|
|
int nfs;
|
|
short *y1;
|
|
short *y2;
|
|
short *iwave;
|
|
} paTestData;
|
|
|
|
// 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 ia=0;
|
|
|
|
if(*data->Transmitting) return 0;
|
|
|
|
if(statusFlags!=0) printf("Status flags %d\n",(int)statusFlags);
|
|
|
|
if((statusFlags&1) == 0) {
|
|
//increment buffer pointers only if data available
|
|
ia=*data->iwrite;
|
|
if(*data->nright==0) { //Use left channel for input
|
|
for(i=0; i<framesPerBuffer; i++) {
|
|
data->y1[ia] = (*in++);
|
|
data->y2[ia] = (*in++);
|
|
ia++;
|
|
}
|
|
} else { //Use right channel
|
|
for(i=0; i<framesPerBuffer; i++) {
|
|
data->y2[ia] = (*in++);
|
|
data->y1[ia] = (*in++);
|
|
ia++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ia >= data->nring) ia=0; //Wrap buffer pointer if necessary
|
|
*data->iwrite = ia; //Save buffer pointer
|
|
iaa=ia;
|
|
total_time += (double)framesPerBuffer/12000.0;
|
|
// printf("iwrite: %d\n",*data->iwrite);
|
|
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 ic=0;
|
|
static int TxOKz=0;
|
|
static clock_t tstart=-1;
|
|
static clock_t tend=-1;
|
|
static int nsent=0;
|
|
|
|
// printf("txOK: %d %d\n",TxOKz,*data->TxOK);
|
|
|
|
if(*data->TxOK && (!TxOKz)) ic=0; //Reset buffer pointer to start Tx
|
|
*data->Transmitting=*data->TxOK; //Set the "transmitting" flag
|
|
|
|
if(*data->TxOK) {
|
|
if(!TxOKz) {
|
|
// Start of a transmission
|
|
tstart=clock();
|
|
nsent=0;
|
|
// printf("Start Tx\n");
|
|
}
|
|
TxOKz=*data->TxOK;
|
|
for(i=0 ; i < framesPerBuffer; i++ ) {
|
|
n2=data->iwave[ic];
|
|
*wptr++ = n2; //left
|
|
*wptr++ = n2; //right
|
|
ic++;
|
|
|
|
if(ic > *data->nwave) {
|
|
*data->TxOK = 0;
|
|
*data->Transmitting = 0;
|
|
*data->iwrite = 0; //Reset Rx buffer pointer to 0
|
|
ic=0;
|
|
tend=clock();
|
|
double TxT=((double)(tend-tstart))/CLOCKS_PER_SEC;
|
|
// printf("End Tx, TxT = %f nSent = %d\n",TxT,nsent);
|
|
break;
|
|
}
|
|
}
|
|
nsent += framesPerBuffer;
|
|
} else {
|
|
memset((void*)outputBuffer, 0, 2*sizeof(short)*framesPerBuffer);
|
|
}
|
|
*data->itx = icc; //Save buffer pointer
|
|
icc=ic;
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************/
|
|
int ft2audio_(int *ndevin, int *ndevout, int *npabuf, int *nright,
|
|
short y1[], short y2[], int *nring, int *iwrite,
|
|
int *itx, short iwave[], int *nwave, int *nfsample,
|
|
int *TxOK, int *Transmitting, int *ngo)
|
|
|
|
{
|
|
paTestData data;
|
|
PaStream *instream, *outstream;
|
|
PaStreamParameters inputParameters, outputParameters;
|
|
// PaStreamInfo *streamInfo;
|
|
|
|
int nfpb = *npabuf;
|
|
int nSampleRate = *nfsample;
|
|
int ndevice_in = *ndevin;
|
|
int ndevice_out = *ndevout;
|
|
double dSampleRate = (double) *nfsample;
|
|
PaError err_init, err_open_in, err_open_out, err_start_in, err_start_out;
|
|
PaError err = 0;
|
|
|
|
data.iwrite = iwrite;
|
|
data.itx = itx;
|
|
data.TxOK = TxOK;
|
|
data.Transmitting = Transmitting;
|
|
data.y1 = y1;
|
|
data.y2 = y2;
|
|
data.nring = *nring;
|
|
data.nright = nright;
|
|
data.nwave = nwave;
|
|
data.iwave = iwave;
|
|
data.nfs = nSampleRate;
|
|
|
|
err_init = Pa_Initialize(); // Initialize PortAudio
|
|
|
|
if(err_init) {
|
|
printf("Error initializing PortAudio.\n");
|
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_init),
|
|
err_init);
|
|
Pa_Terminate(); // I don't think we need this but...
|
|
return(-1);
|
|
}
|
|
|
|
// printf("Opening device %d for input, %d for output...\n",
|
|
// ndevice_in,ndevice_out);
|
|
|
|
inputParameters.device = ndevice_in;
|
|
inputParameters.channelCount = 2;
|
|
inputParameters.sampleFormat = paInt16;
|
|
inputParameters.suggestedLatency = 0.2;
|
|
inputParameters.hostApiSpecificStreamInfo = NULL;
|
|
|
|
// Test if this configuration actually works, so we do not run into an
|
|
// ugly assertion
|
|
err_open_in = Pa_IsFormatSupported(&inputParameters, NULL, dSampleRate);
|
|
|
|
if (err_open_in == 0) {
|
|
err_open_in = Pa_OpenStream(
|
|
&instream, //address of stream
|
|
&inputParameters,
|
|
NULL,
|
|
dSampleRate, //Sample rate
|
|
nfpb, //Frames per buffer
|
|
paNoFlag,
|
|
(PaStreamCallback *)SoundIn, //Callback routine
|
|
(void *)&data); //address of data structure
|
|
|
|
if(err_open_in) { // We should have no error here usually
|
|
printf("Error opening input audio stream:\n");
|
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_in),
|
|
err_open_in);
|
|
err = 1;
|
|
} else {
|
|
// printf("Successfully opened audio input.\n");
|
|
}
|
|
} else {
|
|
printf("Error opening input audio stream.\n");
|
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_in),
|
|
err_open_in);
|
|
err = 1;
|
|
}
|
|
|
|
outputParameters.device = ndevice_out;
|
|
outputParameters.channelCount = 2;
|
|
outputParameters.sampleFormat = paInt16;
|
|
outputParameters.suggestedLatency = 0.2;
|
|
outputParameters.hostApiSpecificStreamInfo = NULL;
|
|
|
|
// Test if this configuration actually works, so we do not run into an
|
|
// ugly assertion.
|
|
err_open_out = Pa_IsFormatSupported(NULL, &outputParameters, dSampleRate);
|
|
|
|
if (err_open_out == 0) {
|
|
err_open_out = Pa_OpenStream(
|
|
&outstream, //address of stream
|
|
NULL,
|
|
&outputParameters,
|
|
dSampleRate, //Sample rate
|
|
nfpb, //Frames per buffer
|
|
paNoFlag,
|
|
(PaStreamCallback *)SoundOut, //Callback routine
|
|
(void *)&data); //address of data structure
|
|
|
|
if(err_open_out) { // We should have no error here usually
|
|
printf("Error opening output audio stream!\n");
|
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_out),
|
|
err_open_out);
|
|
err += 2;
|
|
} else {
|
|
// printf("Successfully opened audio output.\n");
|
|
}
|
|
} else {
|
|
printf("Error opening output audio stream.\n");
|
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_out),
|
|
err_open_out);
|
|
err += 2;
|
|
}
|
|
|
|
// if there was no error in opening both streams start them
|
|
if (err == 0) {
|
|
err_start_in = Pa_StartStream(instream); //Start input stream
|
|
if(err_start_in) {
|
|
printf("Error starting input audio stream!\n");
|
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_start_in),
|
|
err_start_in);
|
|
err += 4;
|
|
}
|
|
|
|
err_start_out = Pa_StartStream(outstream); //Start output stream
|
|
if(err_start_out) {
|
|
printf("Error starting output audio stream!\n");
|
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_start_out),
|
|
err_start_out);
|
|
err += 8;
|
|
}
|
|
}
|
|
|
|
if (err == 0) printf("Audio streams running normally.\n******************************************************************\n");
|
|
|
|
while( Pa_IsStreamActive(instream) && (*ngo != 0) && (err == 0) ) {
|
|
int ic1=0;
|
|
int ic2=0;
|
|
if(_kbhit()) ic1 = _getch();
|
|
if(_kbhit()) ic2 = _getch();
|
|
// if(ic1!=0 || ic2!=0) printf("%d %d %d\n",iaa,ic1,ic2);
|
|
update_(&total_time,&ic1,&ic2);
|
|
Pa_Sleep(100);
|
|
}
|
|
|
|
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(err);
|
|
}
|
|
|
|
|
|
int padevsub_(int *idevin, int *idevout)
|
|
{
|
|
int numdev,ndefin,ndefout;
|
|
int nchin[101], nchout[101];
|
|
int i, devIdx;
|
|
int numDevices;
|
|
const PaDeviceInfo *pdi;
|
|
PaError err;
|
|
|
|
Pa_Initialize();
|
|
numDevices = Pa_GetDeviceCount();
|
|
numdev = numDevices;
|
|
|
|
if( numDevices < 0 ) {
|
|
err = numDevices;
|
|
Pa_Terminate();
|
|
return err;
|
|
}
|
|
|
|
if ((devIdx = Pa_GetDefaultInputDevice()) > 0) {
|
|
ndefin = devIdx;
|
|
} else {
|
|
ndefin = 0;
|
|
}
|
|
|
|
if ((devIdx = Pa_GetDefaultOutputDevice()) > 0) {
|
|
ndefout = devIdx;
|
|
} else {
|
|
ndefout = 0;
|
|
}
|
|
|
|
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_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);
|
|
}
|
|
|
|
printf("\nUser requested devices: Input = %2d Output = %2d\n",
|
|
*idevin,*idevout);
|
|
printf("Default devices: Input = %2d Output = %2d\n",
|
|
ndefin,ndefout);
|
|
if((*idevin<0) || (*idevin>=numdev)) *idevin=ndefin;
|
|
if((*idevout<0) || (*idevout>=numdev)) *idevout=ndefout;
|
|
if((*idevin==0) && (*idevout==0)) {
|
|
*idevin=ndefin;
|
|
*idevout=ndefout;
|
|
}
|
|
printf("Will open devices: Input = %2d Output = %2d\n",
|
|
*idevin,*idevout);
|
|
|
|
Pa_Terminate();
|
|
|
|
return 0;
|
|
}
|
|
|