From 1c86b18b24a2c9916801f791fb67ebd7ae22af51 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Wed, 16 Jun 2021 15:02:40 +0100 Subject: [PATCH] Do necessary COM thread initializations for ASIO audio --- map65/main.cpp | 2 +- map65/soundin.cpp | 121 ++++++++++++++++++++++++++++++--------------- map65/soundin.h | 6 --- map65/soundout.cpp | 32 ++++++++++-- 4 files changed, 111 insertions(+), 50 deletions(-) diff --git a/map65/main.cpp b/map65/main.cpp index 198047ca9..918f64b43 100644 --- a/map65/main.cpp +++ b/map65/main.cpp @@ -19,7 +19,7 @@ int main(int argc, char *argv[]) QApplication a {argc, argv}; // Override programs executable basename as application name. a.setApplicationName ("MAP65"); - a.setApplicationVersion ("3.0.0-rc1"); + a.setApplicationVersion ("3.0.0-devel"); // switch off as we share an Info.plist file with WSJT-X a.setAttribute (Qt::AA_DontUseNativeMenuBar); MainWindow w; diff --git a/map65/soundin.cpp b/map65/soundin.cpp index bca728a4d..0e50f2935 100644 --- a/map65/soundin.cpp +++ b/map65/soundin.cpp @@ -1,45 +1,52 @@ #include "soundin.h" -#include + +#ifdef Q_OS_WIN32 +#include +#else +#include +#endif #define NFFT 32768 #define FRAMES_PER_BUFFER 1024 -extern "C" { #include -extern struct { - double d8[2*60*96000]; //This is "common/datcom/..." in fortran - float ss[4*322*NFFT]; - float savg[4*NFFT]; - double fcenter; - int nutc; - int idphi; //Phase correction for Y pol'n, degrees - int mousedf; //User-selected DF - int mousefqso; //User-selected QSO freq (kHz) - int nagain; //1 ==> decode only at fQSO +/- Tol - int ndepth; //How much hinted decoding to do? - int ndiskdat; //1 ==> data read from *.tf2 or *.iq file - int neme; //Hinted decoding tries only for EME calls - int newdat; //1 ==> new data, must do long FFT - int nfa; //Low decode limit (kHz) - int nfb; //High decode limit (kHz) - int nfcal; //Frequency correction, for calibration (Hz) - int nfshift; //Shift of displayed center freq (kHz) - int mcall3; //1 ==> CALL3.TXT has been modified - int ntimeout; //Max for timeouts in Messages and BandMap - int ntol; //+/- decoding range around fQSO (Hz) - int nxant; //1 ==> add 45 deg to measured pol angle - int map65RxLog; //Flags to control log files - int nfsample; //Input sample rate - int nxpol; //1 if using xpol antennas, 0 otherwise - int mode65; //JT65 sub-mode: A=1, B=2, C=4 - int nfast; //1No longer used - int nsave; //Number of s3(64,63) spectra saved - char mycall[12]; - char mygrid[6]; - char hiscall[12]; - char hisgrid[6]; - char datetime[20]; -} datcom_; +extern "C" +{ + struct + { + double d8[2*60*96000]; //This is "common/datcom/..." in fortran + float ss[4*322*NFFT]; + float savg[4*NFFT]; + double fcenter; + int nutc; + int idphi; //Phase correction for Y pol'n, degrees + int mousedf; //User-selected DF + int mousefqso; //User-selected QSO freq (kHz) + int nagain; //1 ==> decode only at fQSO +/- Tol + int ndepth; //How much hinted decoding to do? + int ndiskdat; //1 ==> data read from *.tf2 or *.iq file + int neme; //Hinted decoding tries only for EME calls + int newdat; //1 ==> new data, must do long FFT + int nfa; //Low decode limit (kHz) + int nfb; //High decode limit (kHz) + int nfcal; //Frequency correction, for calibration (Hz) + int nfshift; //Shift of displayed center freq (kHz) + int mcall3; //1 ==> CALL3.TXT has been modified + int ntimeout; //Max for timeouts in Messages and BandMap + int ntol; //+/- decoding range around fQSO (Hz) + int nxant; //1 ==> add 45 deg to measured pol angle + int map65RxLog; //Flags to control log files + int nfsample; //Input sample rate + int nxpol; //1 if using xpol antennas, 0 otherwise + int mode65; //JT65 sub-mode: A=1, B=2, C=4 + int nfast; //1No longer used + int nsave; //Number of s3(64,63) spectra saved + char mycall[12]; + char mygrid[6]; + char hiscall[12]; + char hisgrid[6]; + char datetime[20]; + } datcom_; } typedef struct @@ -133,6 +140,26 @@ extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer, return paContinue; } +namespace +{ + struct COMWrapper + { + explicit COMWrapper () + { +#ifdef Q_OS_WIN32 + // required because Qt only does this for GUI thread + CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); +#endif + } + ~COMWrapper () + { +#ifdef Q_OS_WIN32 + CoUninitialize (); +#endif + } + }; +} + void SoundInThread::run() //SoundInThread::run() { quitExecution = false; @@ -144,8 +171,10 @@ void SoundInThread::run() //SoundInThread::run() return; } -//---------------------------------------------------- Soundcard Setup -// qDebug() << "Start souncard input"; + COMWrapper c; + + //---------------------------------------------------- Soundcard Setup + // qDebug() << "Start souncard input"; PaError paerr; PaStreamParameters inParam; @@ -158,15 +187,27 @@ void SoundInThread::run() //SoundInThread::run() udata.iqswap=m_IQswap; udata.b10db=m_10db; + auto device_info = Pa_GetDeviceInfo (m_nDevIn); + inParam.device=m_nDevIn; //### Input Device Number ### inParam.channelCount=2*m_nrx; //Number of analog channels inParam.sampleFormat=paFloat32; //Get floats from Portaudio - inParam.suggestedLatency=0.05; + inParam.suggestedLatency=device_info->defaultHighInputLatency; inParam.hostApiSpecificStreamInfo=NULL; paerr=Pa_IsFormatSupported(&inParam,NULL,96000.0); if(paerr<0) { - emit error("PortAudio says requested soundcard format not supported."); + QString error_message; + if (paUnanticipatedHostError == paerr) + { + auto const * last_host_error = Pa_GetLastHostErrorInfo (); + error_message = QString {"PortAudio Host API error: %1"}.arg (last_host_error->errorText); + } + else + { + error_message = "PortAudio says requested soundcard format not supported."; + } + emit error(error_message); // return; } paerr=Pa_OpenStream(&inStream, //Input stream diff --git a/map65/soundin.h b/map65/soundin.h index 5e53e7ef8..369cf1d71 100644 --- a/map65/soundin.h +++ b/map65/soundin.h @@ -6,12 +6,6 @@ #include #include -#ifdef Q_OS_WIN32 -#include -#else -#include -#endif //Q_OS_WIN32 - // Thread gets audio data from soundcard and signals when a buffer of // specified size is available. class SoundInThread : public QThread diff --git a/map65/soundout.cpp b/map65/soundout.cpp index fdc2f745b..e74d0549d 100644 --- a/map65/soundout.cpp +++ b/map65/soundout.cpp @@ -1,10 +1,12 @@ #include "soundout.h" +#ifdef Q_OS_WIN32 +#include +#endif + #define FRAMES_PER_BUFFER 256 -extern "C" { #include -} extern float gran(); //Noise generator (for tests only) @@ -120,18 +122,42 @@ extern "C" int d2aCallback(const void * /*inputBuffer*/, void *outputBuffer, return 0; } +namespace +{ + struct COMWrapper + { + explicit COMWrapper () + { +#ifdef Q_OS_WIN32 + // required because Qt only does this for GUI thread + CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); +#endif + } + ~COMWrapper () + { +#ifdef Q_OS_WIN32 + CoUninitialize (); +#endif + } + }; +} + void SoundOutThread::run() { + COMWrapper c; + PaError paerr; PaStreamParameters outParam; PaStream *outStream; paUserData udata; quitExecution = false; + auto device_info = Pa_GetDeviceInfo (m_nDevOut); + outParam.device=m_nDevOut; //Output device number outParam.channelCount=2; //Number of analog channels outParam.sampleFormat=paInt16; //Send short ints to PortAudio - outParam.suggestedLatency=0.05; + outParam.suggestedLatency=device_info->defaultLowOutputLatency; outParam.hostApiSpecificStreamInfo=NULL; udata.nTRperiod=m_TRperiod;