mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-22 04:11:16 -05:00
Most of these changes are thanks to G4WJS. Audio I/O is now done using
Qt's built-in QAudio calls rather than PortAudio. Also includes some refactoring of the arrangement for these calls, and more use of C++ style. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3523 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
e9f9180088
commit
61f023ddd1
@ -3,13 +3,12 @@
|
||||
|
||||
#define NSMAX 6827
|
||||
#define NTMAX 120
|
||||
#define RX_SAMPLE_RATE 12000
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern struct {
|
||||
extern struct FortranCommon {
|
||||
float ss[184*NSMAX]; //This is "common/jt9com/..." in fortran
|
||||
float savg[NSMAX];
|
||||
short int d2[NTMAX*12000];
|
||||
short int d2[NTMAX*RX_SAMPLE_RATE];
|
||||
int nutc; //UTC as integer, HHMM
|
||||
int ndiskdat; //1 ==> data read from *.wav file
|
||||
int ntrperiod; //TR period (seconds)
|
||||
@ -29,6 +28,4 @@ extern struct {
|
||||
char datetime[20];
|
||||
} jt9com_;
|
||||
|
||||
}
|
||||
|
||||
#endif // COMMONS_H
|
||||
|
162
devsetup.cpp
162
devsetup.cpp
@ -1,7 +1,6 @@
|
||||
#include "devsetup.h"
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
#include <portaudio.h>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioInput>
|
||||
|
||||
@ -12,7 +11,10 @@ qint32 g2_iptt;
|
||||
qint32 g2_COMportOpen;
|
||||
|
||||
//----------------------------------------------------------- DevSetup()
|
||||
DevSetup::DevSetup(QWidget *parent) : QDialog(parent)
|
||||
DevSetup::DevSetup(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_audioInputDevices (QAudioDeviceInfo::availableDevices (QAudio::AudioInput))
|
||||
, m_audioOutputDevices (QAudioDeviceInfo::availableDevices (QAudio::AudioOutput))
|
||||
{
|
||||
ui.setupUi(this); //setup the dialog form
|
||||
m_restartSoundIn=false;
|
||||
@ -37,109 +39,43 @@ void DevSetup::initDlg()
|
||||
QString catPortDriver = settings.value("CATdriver","None").toString();
|
||||
settings.endGroup();
|
||||
|
||||
/*
|
||||
QList<QAudioDeviceInfo> InDevices;
|
||||
QList<QAudioDeviceInfo> OutDevices;
|
||||
QAudioDeviceInfo deviceInfo;
|
||||
|
||||
InDevices = deviceInfo.availableDevices(QAudio::AudioInput);
|
||||
OutDevices = deviceInfo.availableDevices(QAudio::AudioOutput);
|
||||
|
||||
foreach (const QAudioDeviceInfo &deviceInfo, InDevices) {
|
||||
ui.comboBoxSndIn->addItem(deviceInfo.deviceName(),
|
||||
qVariantFromValue(deviceInfo));
|
||||
}
|
||||
|
||||
foreach (const QAudioDeviceInfo &deviceInfo, OutDevices) {
|
||||
ui.comboBoxSndOut->addItem(deviceInfo.deviceName(),
|
||||
qVariantFromValue(deviceInfo));
|
||||
}
|
||||
*/
|
||||
|
||||
int k,id;
|
||||
int numDevices=Pa_GetDeviceCount();
|
||||
|
||||
const PaDeviceInfo *pdi;
|
||||
int nchin;
|
||||
int nchout;
|
||||
char pa_device_name[128];
|
||||
char pa_device_hostapi[128];
|
||||
|
||||
k=0;
|
||||
for(id=0; id<numDevices; id++ ) {
|
||||
pdi=Pa_GetDeviceInfo(id);
|
||||
nchin=pdi->maxInputChannels;
|
||||
if(nchin>0) {
|
||||
m_inDevList[k]=id;
|
||||
if (id == m_paInDevice)
|
||||
m_nDevIn = k;
|
||||
k++;
|
||||
sprintf((char*)(pa_device_name),"%s",pdi->name);
|
||||
sprintf((char*)(pa_device_hostapi),"%s",
|
||||
Pa_GetHostApiInfo(pdi->hostApi)->name);
|
||||
|
||||
#ifdef WIN32
|
||||
char *p,*p1;
|
||||
char p2[50];
|
||||
p1=(char*)"";
|
||||
p=strstr(pa_device_hostapi,"MME");
|
||||
if(p!=NULL) p1=(char*)"MME";
|
||||
p=strstr(pa_device_hostapi,"Direct");
|
||||
if(p!=NULL) p1=(char*)"DirectX";
|
||||
p=strstr(pa_device_hostapi,"WASAPI");
|
||||
if(p!=NULL) p1=(char*)"WASAPI";
|
||||
p=strstr(pa_device_hostapi,"ASIO");
|
||||
if(p!=NULL) p1=(char*)"ASIO";
|
||||
p=strstr(pa_device_hostapi,"WDM-KS");
|
||||
if(p!=NULL) p1=(char*)"WDM-KS";
|
||||
|
||||
sprintf(p2,"%2d %d %-8s %-39s",id,nchin,p1,pa_device_name);
|
||||
QString t(p2);
|
||||
#else
|
||||
QString t;
|
||||
t.sprintf("%2d %d %-8s %-39s",id,nchin,
|
||||
Pa_GetHostApiInfo(pdi->hostApi)->name,pdi->name);
|
||||
#endif
|
||||
ui.comboBoxSndIn->addItem(t);
|
||||
}
|
||||
//
|
||||
// loaad combo boxes with setup choices
|
||||
//
|
||||
{
|
||||
int currentIndex = -1;
|
||||
int defaultIndex = 0;
|
||||
for (AudioDevices::const_iterator p = m_audioInputDevices.begin (); p != m_audioInputDevices.end (); ++p)
|
||||
{
|
||||
ui.comboBoxSndIn->addItem (p->deviceName ());
|
||||
if (*p == m_audioInputDevice)
|
||||
{
|
||||
currentIndex = p - m_audioInputDevices.begin ();
|
||||
}
|
||||
else if (*p == QAudioDeviceInfo::defaultInputDevice ())
|
||||
{
|
||||
defaultIndex = p - m_audioInputDevices.begin ();
|
||||
}
|
||||
}
|
||||
ui.comboBoxSndIn->setCurrentIndex (currentIndex != -1 ? currentIndex : defaultIndex);
|
||||
}
|
||||
|
||||
k=0;
|
||||
for(id=0; id<numDevices; id++ ) {
|
||||
pdi=Pa_GetDeviceInfo(id);
|
||||
nchout=pdi->maxOutputChannels;
|
||||
if(nchout>0) {
|
||||
m_outDevList[k]=id;
|
||||
if (id == m_paOutDevice)
|
||||
m_nDevOut = k;
|
||||
k++;
|
||||
sprintf((char*)(pa_device_name),"%s",pdi->name);
|
||||
sprintf((char*)(pa_device_hostapi),"%s",
|
||||
Pa_GetHostApiInfo(pdi->hostApi)->name);
|
||||
|
||||
#ifdef WIN32
|
||||
char *p,*p1;
|
||||
char p2[50];
|
||||
p1=(char*)"";
|
||||
p=strstr(pa_device_hostapi,"MME");
|
||||
if(p!=NULL) p1=(char*)"MME";
|
||||
p=strstr(pa_device_hostapi,"Direct");
|
||||
if(p!=NULL) p1=(char*)"DirectX";
|
||||
p=strstr(pa_device_hostapi,"WASAPI");
|
||||
if(p!=NULL) p1=(char*)"WASAPI";
|
||||
p=strstr(pa_device_hostapi,"ASIO");
|
||||
if(p!=NULL) p1=(char*)"ASIO";
|
||||
p=strstr(pa_device_hostapi,"WDM-KS");
|
||||
if(p!=NULL) p1=(char*)"WDM-KS";
|
||||
sprintf(p2,"%2d %d %-8s %-39s",id,nchout,p1,pa_device_name);
|
||||
QString t(p2);
|
||||
#else
|
||||
QString t;
|
||||
t.sprintf("%2d %d %-8s %-39s",id,nchout,
|
||||
Pa_GetHostApiInfo(pdi->hostApi)->name,pdi->name);
|
||||
#endif
|
||||
ui.comboBoxSndOut->addItem(t);
|
||||
}
|
||||
{
|
||||
int currentIndex = -1;
|
||||
int defaultIndex = 0;
|
||||
for (AudioDevices::const_iterator p = m_audioOutputDevices.begin (); p != m_audioOutputDevices.end (); ++p)
|
||||
{
|
||||
ui.comboBoxSndOut->addItem (p->deviceName ());
|
||||
if (*p == m_audioOutputDevice)
|
||||
{
|
||||
currentIndex = p - m_audioOutputDevices.begin ();
|
||||
}
|
||||
else if (*p == QAudioDeviceInfo::defaultOutputDevice ())
|
||||
{
|
||||
defaultIndex = p - m_audioOutputDevices.begin ();
|
||||
}
|
||||
}
|
||||
ui.comboBoxSndOut->setCurrentIndex (currentIndex != -1 ? currentIndex : defaultIndex);
|
||||
}
|
||||
|
||||
connect(&p4, SIGNAL(readyReadStandardOutput()),
|
||||
@ -167,8 +103,6 @@ void DevSetup::initDlg()
|
||||
ui.idIntSpinBox->setValue(m_idInt);
|
||||
ui.pttMethodComboBox->setCurrentIndex(m_pttMethodIndex);
|
||||
ui.saveDirEntry->setText(m_saveDir);
|
||||
ui.comboBoxSndIn->setCurrentIndex(m_nDevIn);
|
||||
ui.comboBoxSndOut->setCurrentIndex(m_nDevOut);
|
||||
ui.cbID73->setChecked(m_After73);
|
||||
ui.cbPSKReporter->setChecked(m_pskReporter);
|
||||
ui.cbSplit->setChecked(m_bSplit and m_catEnabled);
|
||||
@ -302,11 +236,17 @@ void DevSetup::accept()
|
||||
// Check to see whether SoundInThread must be restarted,
|
||||
// and save user parameters.
|
||||
|
||||
if(m_nDevIn!=ui.comboBoxSndIn->currentIndex() or
|
||||
m_paInDevice!=m_inDevList[m_nDevIn]) m_restartSoundIn=true;
|
||||
if (m_audioInputDevice != m_audioInputDevices[ui.comboBoxSndIn->currentIndex ()])
|
||||
{
|
||||
m_audioInputDevice = m_audioInputDevices[ui.comboBoxSndIn->currentIndex ()];
|
||||
m_restartSoundIn = true;
|
||||
}
|
||||
|
||||
if(m_nDevOut!=ui.comboBoxSndOut->currentIndex() or
|
||||
m_paOutDevice!=m_outDevList[m_nDevOut]) m_restartSoundOut=true;
|
||||
if (m_audioOutputDevice != m_audioOutputDevices[ui.comboBoxSndOut->currentIndex ()])
|
||||
{
|
||||
m_audioOutputDevice = m_audioOutputDevices[ui.comboBoxSndOut->currentIndex ()];
|
||||
m_restartSoundOut = true;
|
||||
}
|
||||
|
||||
m_myCall=ui.myCallEntry->text();
|
||||
m_myGrid=ui.myGridEntry->text();
|
||||
@ -314,10 +254,6 @@ void DevSetup::accept()
|
||||
m_pttMethodIndex=ui.pttMethodComboBox->currentIndex();
|
||||
m_pttPort=ui.pttComboBox->currentIndex();
|
||||
m_saveDir=ui.saveDirEntry->text();
|
||||
m_nDevIn=ui.comboBoxSndIn->currentIndex();
|
||||
m_paInDevice=m_inDevList[m_nDevIn];
|
||||
m_nDevOut=ui.comboBoxSndOut->currentIndex();
|
||||
m_paOutDevice=m_outDevList[m_nDevOut];
|
||||
|
||||
m_macro.clear();
|
||||
m_macro.append(ui.macro1->text());
|
||||
|
17
devsetup.h
17
devsetup.h
@ -1,10 +1,13 @@
|
||||
#ifndef DEVSETUP_H
|
||||
#define DEVSETUP_H
|
||||
|
||||
#include "ui_devsetup.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QProcess>
|
||||
#include <QMessageBox>
|
||||
#include "ui_devsetup.h"
|
||||
#include <QAudioDeviceInfo>
|
||||
|
||||
#include "rigclass.h"
|
||||
|
||||
class DevSetup : public QDialog
|
||||
@ -19,12 +22,6 @@ public:
|
||||
qint32 m_idInt;
|
||||
qint32 m_pttMethodIndex;
|
||||
qint32 m_pttPort;
|
||||
qint32 m_nDevIn;
|
||||
qint32 m_nDevOut;
|
||||
qint32 m_inDevList[100];
|
||||
qint32 m_outDevList[100];
|
||||
qint32 m_paInDevice;
|
||||
qint32 m_paOutDevice;
|
||||
qint32 m_catPortIndex;
|
||||
qint32 m_rig;
|
||||
qint32 m_rigIndex;
|
||||
@ -39,8 +36,14 @@ public:
|
||||
qint32 m_poll;
|
||||
qint32 m_tmp;
|
||||
|
||||
typedef QList<QAudioDeviceInfo> AudioDevices;
|
||||
AudioDevices m_audioInputDevices; /* available input devices */
|
||||
AudioDevices m_audioOutputDevices; /* available output devices */
|
||||
QAudioDeviceInfo m_audioInputDevice; /* selected input device */
|
||||
QAudioDeviceInfo m_audioOutputDevice; /* selected output device */
|
||||
bool m_restartSoundIn;
|
||||
bool m_restartSoundOut;
|
||||
|
||||
bool m_pskReporter;
|
||||
bool m_firstCall;
|
||||
bool m_catEnabled;
|
||||
|
@ -9,8 +9,8 @@ EXE_DIR = ../../wsjtx_install
|
||||
# -I'c:/QtSDK/Desktop/Qt/4.7.4/mingw/include/ActiveQt' \
|
||||
# -I'release' -I'.' -I'c:/QtSDK/Desktop/Qt/4.7.4/mingw/mkspecs/win32-g++'
|
||||
|
||||
INCPATH = -I'C:/Qt/Qt5.0.2/5.0.2/mingw47_32/include/QtCore' \
|
||||
-I'C:/Qt/Qt5.0.2/5.0.2/mingw47_32/include' \
|
||||
INCPATH = -I'C:/Qt/Qt5.1.0/5.1.0/mingw48_32/include/QtCore' \
|
||||
-I'C:/Qt/Qt5.1.0/5.1.0/mingw48_32/include' \
|
||||
|
||||
# Compilers
|
||||
CC = gcc
|
||||
@ -57,11 +57,10 @@ libjt9.a: $(OBJS1)
|
||||
ranlib libjt9.a
|
||||
|
||||
OBJS2 = jt9.o jt9a.o jt9b.o jt9c.o ipcomm.o sec_midn.o usleep.o
|
||||
#LIBS2 = -L'c:/QtSDK/Desktop/Qt/4.7.4/mingw/lib' -lQtCore4
|
||||
LIBS2 = -L'C:/Qt/Qt5.0.2/5.0.2/mingw47_32/lib' -lQt5Core
|
||||
LIBS2 = -L'C:/Qt/Qt5.1.0/5.1.0/mingw48_32/lib' -lQt5Core
|
||||
jt9.exe: $(OBJS2) libjt9.a
|
||||
$(CXX) -o jt9.exe $(OBJS2) $(LIBS2) libjt9.a ../libfftw3f_win.a \
|
||||
c:/MinGW/lib/libf95.a
|
||||
$(CXX) -o jt9.exe -static $(OBJS2) $(LIBS2) libjt9.a \
|
||||
../libfftw3f_win.a c:/MinGW/lib/libf95.a
|
||||
mkdir -p $(EXE_DIR)
|
||||
cp jt9.exe $(EXE_DIR)
|
||||
|
||||
|
5
lib/usleep.c
Normal file
5
lib/usleep.c
Normal file
@ -0,0 +1,5 @@
|
||||
/* usleep(3) */
|
||||
void usleep_(unsigned long *microsec)
|
||||
{
|
||||
usleep(*microsec);
|
||||
}
|
10
main.cpp
10
main.cpp
@ -4,9 +4,10 @@
|
||||
#include <QtGui>
|
||||
#endif
|
||||
#include <QApplication>
|
||||
#include <portaudio.h>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
|
||||
// Multiple instances:
|
||||
QSharedMemory mem_jt9;
|
||||
QUuid my_uuid;
|
||||
@ -48,13 +49,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
memset(to,0,size); //Zero all decoding params in shared memory
|
||||
|
||||
//Initialize Portaudio
|
||||
PaError paerr=Pa_Initialize();
|
||||
if(paerr!=paNoError) {
|
||||
QMessageBox::critical( 0, "Error", "Unable to initialize PortAudio.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Multiple instances: Call MainWindow() with the UUID key
|
||||
MainWindow w(&mem_jt9, &my_key, fontSize2, fontWeight2);
|
||||
w.show();
|
||||
|
216
mainwindow.cpp
216
mainwindow.cpp
@ -1,13 +1,17 @@
|
||||
//--------------------------------------------------------------- MainWindow
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QScopedPointer>
|
||||
|
||||
#include "devsetup.h"
|
||||
#include "plotter.h"
|
||||
#include "about.h"
|
||||
#include "widegraph.h"
|
||||
#include "sleep.h"
|
||||
#include "getfile.h"
|
||||
#include <portaudio.h>
|
||||
#include "logqso.h"
|
||||
|
||||
#ifdef QT5
|
||||
@ -15,8 +19,14 @@
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#endif
|
||||
|
||||
int itone[126]; //Audio tones for all Tx symbols
|
||||
int icw[250]; //Dits for CW ID
|
||||
#define NUM_JT65_SYMBOLS 126
|
||||
#define NUM_JT9_SYMBOLS 85
|
||||
#define NUM_CW_SYMBOLS 250
|
||||
#define TX_SAMPLE_RATE 48000
|
||||
|
||||
int itone[NUM_JT65_SYMBOLS]; //Audio tones for all Tx symbols
|
||||
int icw[NUM_CW_SYMBOLS]; //Dits for CW ID
|
||||
|
||||
int outBufSize;
|
||||
int rc;
|
||||
qint32 g_COMportOpen;
|
||||
@ -41,10 +51,16 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
|
||||
qint32 fontSize2, qint32 fontWeight2, \
|
||||
QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
ui(new Ui::MainWindow),
|
||||
m_audioInputDevice (QAudioDeviceInfo::defaultInputDevice ()), // start with default
|
||||
m_detector (RX_SAMPLE_RATE, NTMAX / 2, 6912 / 2 * sizeof (jt9com_.d2[0]), this),
|
||||
m_audioOutputDevice (QAudioDeviceInfo::defaultOutputDevice ()), // start with default
|
||||
m_modulator (TX_SAMPLE_RATE, NTMAX / 2, this)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_detector.open ();
|
||||
|
||||
on_EraseButton_clicked();
|
||||
QActionGroup* paletteGroup = new QActionGroup(this);
|
||||
ui->actionCuteSDR->setActionGroup(paletteGroup);
|
||||
@ -83,12 +99,15 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
|
||||
SLOT(doubleClickOnCall2(bool,bool)));
|
||||
|
||||
setWindowTitle(Program_Title_Version);
|
||||
connect(&m_soundInput, SIGNAL(readyForFFT(int)),
|
||||
this, SLOT(dataSink(int)));
|
||||
connect(&m_detector, &Detector::bytesWritten, this, &MainWindow::dataSink);
|
||||
connect(&m_soundInput, SIGNAL(error(QString)), this,
|
||||
SLOT(showSoundInError(QString)));
|
||||
connect(&m_soundOutput, SIGNAL(error(QString)), this,
|
||||
SLOT(showSoundOutError(QString)));
|
||||
connect(&m_soundInput, SIGNAL(status(QString)), this,
|
||||
SLOT(showStatusMessage(QString)));
|
||||
// connect(&m_soundOutput, SIGNAL(status(QString)), this,
|
||||
// SLOT(showStatusMessage(QString)));
|
||||
createStatusBar();
|
||||
|
||||
connect(&proc_jt9, SIGNAL(readyReadStandardOutput()),
|
||||
@ -146,7 +165,7 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
|
||||
m_auto=false;
|
||||
m_waterfallAvg = 1;
|
||||
m_txFirst=false;
|
||||
m_soundOutput.mute(false);
|
||||
m_modulator.mute(false);
|
||||
m_btxMute=false;
|
||||
m_btxok=false;
|
||||
m_restart=false;
|
||||
@ -299,11 +318,11 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
|
||||
watcher2 = new QFutureWatcher<void>;
|
||||
connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished()));
|
||||
|
||||
m_soundInput.start(m_paInDevice);
|
||||
m_soundOutput.setTxFreq(m_txFreq);
|
||||
m_soundOutput.tune(false);
|
||||
m_soundInput.start(m_audioInputDevice, RX_SAMPLE_RATE / 10, &m_detector);
|
||||
m_modulator.setFrequency(m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
|
||||
m_modulator.tune(false);
|
||||
m_monitoring=!m_monitorStartOFF; // Start with Monitoring ON/OFF
|
||||
m_soundInput.setMonitoring(m_monitoring);
|
||||
m_detector.setMonitoring(m_monitoring);
|
||||
m_diskData=false;
|
||||
|
||||
// Create "m_worked", a dictionary of all calls in wsjtx.log
|
||||
@ -371,10 +390,12 @@ MainWindow::~MainWindow()
|
||||
{
|
||||
writeSettings();
|
||||
m_soundOutput.stop();
|
||||
m_modulator.close();
|
||||
if(!m_decoderBusy) {
|
||||
QFile lockFile(m_appDir + "/.lock");
|
||||
lockFile.remove();
|
||||
}
|
||||
m_detector.close ();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
@ -404,19 +425,8 @@ void MainWindow::writeSettings()
|
||||
settings.setValue("PTTmethod",m_pttMethodIndex);
|
||||
settings.setValue("PTTport",m_pttPort);
|
||||
settings.setValue("SaveDir",m_saveDir);
|
||||
char soundName[128];
|
||||
if (Pa_GetDeviceInfo( m_paInDevice)) { // store name, number may be different next time
|
||||
snprintf( soundName, sizeof( soundName), "%s:%s",
|
||||
Pa_GetHostApiInfo( Pa_GetDeviceInfo( m_paInDevice)->hostApi)->name,
|
||||
Pa_GetDeviceInfo( m_paInDevice)->name);
|
||||
settings.setValue("SoundInName", soundName);
|
||||
}
|
||||
if (Pa_GetDeviceInfo( m_paOutDevice)) { // store name, number may be different next time
|
||||
snprintf( soundName, sizeof( soundName), "%s:%s",
|
||||
Pa_GetHostApiInfo( Pa_GetDeviceInfo( m_paOutDevice)->hostApi)->name,
|
||||
Pa_GetDeviceInfo( m_paOutDevice)->name);
|
||||
settings.setValue("SoundOutName", soundName);
|
||||
}
|
||||
settings.setValue("SoundInName", m_audioInputDevice.deviceName ());
|
||||
settings.setValue("SoundOutName", m_audioOutputDevice.deviceName ());
|
||||
settings.setValue("PaletteCuteSDR",ui->actionCuteSDR->isChecked());
|
||||
settings.setValue("PaletteLinrad",ui->actionLinrad->isChecked());
|
||||
settings.setValue("PaletteAFMHot",ui->actionAFMHot->isChecked());
|
||||
@ -511,33 +521,34 @@ void MainWindow::readSettings()
|
||||
m_pttPort=settings.value("PTTport",0).toInt();
|
||||
m_saveDir=settings.value("SaveDir",m_appDir + "/save").toString();
|
||||
|
||||
char soundName[128];
|
||||
QString savedName = settings.value( "SoundInName", "default").toString();
|
||||
for (m_paInDevice = Pa_GetDeviceCount() - 1; m_paInDevice >= 0; m_paInDevice--) {
|
||||
snprintf( soundName, sizeof( soundName), "%s:%s",
|
||||
Pa_GetHostApiInfo( Pa_GetDeviceInfo( m_paInDevice)->hostApi)->name,
|
||||
Pa_GetDeviceInfo( m_paInDevice)->name);
|
||||
if ((savedName == soundName) && (Pa_GetDeviceInfo(m_paInDevice)->maxInputChannels > 0))
|
||||
break;
|
||||
}
|
||||
if (m_paInDevice < 0) { // no match for device name?
|
||||
m_paInDevice = Pa_GetDefaultInputDevice();
|
||||
if (m_paInDevice == paNoDevice) // no default input device?
|
||||
m_paInDevice = 0;
|
||||
{
|
||||
//
|
||||
// retrieve audio input device
|
||||
//
|
||||
QString savedName = settings.value( "SoundInName", "default").toString();
|
||||
QList<QAudioDeviceInfo> audioInputDevices (QAudioDeviceInfo::availableDevices (QAudio::AudioInput)); // available audio input devices
|
||||
for (QList<QAudioDeviceInfo>::const_iterator p = audioInputDevices.begin (); p != audioInputDevices.end (); ++p)
|
||||
{
|
||||
if (p->deviceName () == savedName)
|
||||
{
|
||||
m_audioInputDevice = *p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
savedName = settings.value("SoundOutName", "default").toString();
|
||||
for (m_paOutDevice = Pa_GetDeviceCount() - 1; m_paOutDevice >= 0; m_paOutDevice--) {
|
||||
snprintf( soundName, sizeof( soundName), "%s:%s",
|
||||
Pa_GetHostApiInfo( Pa_GetDeviceInfo( m_paOutDevice)->hostApi)->name,
|
||||
Pa_GetDeviceInfo( m_paOutDevice)->name);
|
||||
if ((savedName == soundName) && (Pa_GetDeviceInfo(m_paOutDevice)->maxOutputChannels > 0))
|
||||
break;
|
||||
}
|
||||
if (m_paOutDevice < 0) { // no match for device name?
|
||||
m_paOutDevice = Pa_GetDefaultOutputDevice();
|
||||
if (m_paOutDevice == paNoDevice) // no default output device?
|
||||
m_paOutDevice = 0;
|
||||
{
|
||||
//
|
||||
// retrieve audio output device
|
||||
//
|
||||
QString savedName = settings.value("SoundOutName", "default").toString();
|
||||
QList<QAudioDeviceInfo> audioOutputDevices (QAudioDeviceInfo::availableDevices (QAudio::AudioOutput)); // available audio output devices
|
||||
for (QList<QAudioDeviceInfo>::const_iterator p = audioOutputDevices.begin (); p != audioOutputDevices.end (); ++p)
|
||||
{
|
||||
if (p->deviceName () == savedName)
|
||||
{
|
||||
m_audioOutputDevice = *p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->actionCuteSDR->setChecked(settings.value(
|
||||
@ -563,7 +574,7 @@ void MainWindow::readSettings()
|
||||
ui->RxFreqSpinBox->setValue(m_rxFreq);
|
||||
m_txFreq=settings.value("TxFreq",1500).toInt();
|
||||
ui->TxFreqSpinBox->setValue(m_txFreq);
|
||||
m_soundOutput.setTxFreq(m_txFreq);
|
||||
m_modulator.setFrequency(m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
|
||||
m_saveDecoded=ui->actionSave_decoded->isChecked();
|
||||
m_saveAll=ui->actionSave_all->isChecked();
|
||||
m_ndepth=settings.value("NDepth",3).toInt();
|
||||
@ -655,7 +666,7 @@ void MainWindow::readSettings()
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------- dataSink()
|
||||
void MainWindow::dataSink(int k)
|
||||
void MainWindow::dataSink(qint64 bytes)
|
||||
{
|
||||
static float s[NSMAX];
|
||||
static int ihsym=0;
|
||||
@ -676,6 +687,7 @@ void MainWindow::dataSink(int k)
|
||||
trmin=m_TRperiod/60;
|
||||
slope=0.0;
|
||||
if(g_pWideGraph!=NULL) slope=(float)g_pWideGraph->getSlope();
|
||||
int k (bytes / sizeof (jt9com_.d2[0]) - 1);
|
||||
symspec_(&k,&trmin,&m_nsps,&m_inGain,&slope,&px,s,&df3,&ihsym,&npts8);
|
||||
if(ihsym <=0) return;
|
||||
QString t;
|
||||
@ -710,7 +722,10 @@ void MainWindow::dataSink(int k)
|
||||
}
|
||||
|
||||
void MainWindow::showSoundInError(const QString& errorMsg)
|
||||
{QMessageBox::critical(this, tr("Error in SoundIn"), errorMsg);}
|
||||
{QMessageBox::critical(this, tr("Error in SoundInput"), errorMsg);}
|
||||
|
||||
void MainWindow::showSoundOutError(const QString& errorMsg)
|
||||
{QMessageBox::critical(this, tr("Error in SoundOutput"), errorMsg);}
|
||||
|
||||
void MainWindow::showStatusMessage(const QString& statusMsg)
|
||||
{statusBar()->showMessage(statusMsg);}
|
||||
@ -724,8 +739,8 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
|
||||
dlg.m_pttMethodIndex=m_pttMethodIndex;
|
||||
dlg.m_pttPort=m_pttPort;
|
||||
dlg.m_saveDir=m_saveDir;
|
||||
dlg.m_paInDevice=m_paInDevice;
|
||||
dlg.m_paOutDevice=m_paOutDevice;
|
||||
dlg.m_audioInputDevice = m_audioInputDevice;
|
||||
dlg.m_audioOutputDevice = m_audioOutputDevice;
|
||||
dlg.m_pskReporter=m_pskReporter;
|
||||
dlg.m_After73=m_After73;
|
||||
dlg.m_macro=m_macro;
|
||||
@ -769,8 +784,8 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
|
||||
m_pttMethodIndex=dlg.m_pttMethodIndex;
|
||||
m_pttPort=dlg.m_pttPort;
|
||||
m_saveDir=dlg.m_saveDir;
|
||||
m_paInDevice=dlg.m_paInDevice;
|
||||
m_paOutDevice=dlg.m_paOutDevice;
|
||||
m_audioInputDevice = dlg.m_audioInputDevice;
|
||||
m_audioOutputDevice = dlg.m_audioOutputDevice;
|
||||
m_macro=dlg.m_macro;
|
||||
m_dFreq=dlg.m_dFreq;
|
||||
m_antDescription=dlg.m_antDescription;
|
||||
@ -826,11 +841,11 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
|
||||
m_After73=dlg.m_After73;
|
||||
|
||||
if(dlg.m_restartSoundIn) {
|
||||
m_soundInput.start(m_paInDevice);
|
||||
m_soundInput.start(m_audioInputDevice, RX_SAMPLE_RATE / 10, &m_detector);
|
||||
}
|
||||
|
||||
if(dlg.m_restartSoundOut) {
|
||||
m_soundOutput.start(m_paOutDevice,m_modeTx,m_TRperiod,m_nsps,m_txFreq,m_bSplit || m_bXIT ? m_XIT : 0);
|
||||
transmit ();
|
||||
}
|
||||
}
|
||||
m_catEnabled=dlg.m_catEnabled;
|
||||
@ -859,7 +874,7 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
|
||||
void MainWindow::on_monitorButton_clicked() //Monitor
|
||||
{
|
||||
m_monitoring=true;
|
||||
m_soundInput.setMonitoring(true);
|
||||
m_detector.setMonitoring(true);
|
||||
m_diskData=false;
|
||||
}
|
||||
|
||||
@ -901,7 +916,7 @@ void MainWindow::on_autoButton_clicked() //Auto
|
||||
ui->autoButton->setStyleSheet(m_pbAutoOn_style);
|
||||
} else {
|
||||
m_btxok=false;
|
||||
m_soundOutput.mute();
|
||||
m_modulator.mute();
|
||||
ui->autoButton->setStyleSheet("");
|
||||
on_monitorButton_clicked();
|
||||
m_repeatMsg=0;
|
||||
@ -1122,7 +1137,7 @@ void MainWindow::OnExit()
|
||||
void MainWindow::on_stopButton_clicked() //stopButton
|
||||
{
|
||||
m_monitoring=false;
|
||||
m_soundInput.setMonitoring(m_monitoring);
|
||||
m_detector.setMonitoring(m_monitoring);
|
||||
m_loopall=false;
|
||||
}
|
||||
|
||||
@ -1163,7 +1178,7 @@ void MainWindow::on_actionWide_Waterfall_triggered() //Display Waterfalls
|
||||
void MainWindow::on_actionOpen_triggered() //Open File
|
||||
{
|
||||
m_monitoring=false;
|
||||
m_soundInput.setMonitoring(m_monitoring);
|
||||
m_detector.setMonitoring(m_monitoring);
|
||||
QString fname;
|
||||
fname=QFileDialog::getOpenFileName(this, "Open File", m_path,
|
||||
"WSJT Files (*.wav)");
|
||||
@ -1223,7 +1238,7 @@ void MainWindow::diskDat() //diskDat()
|
||||
for(int n=1; n<=m_hsymStop; n++) { // Do the half-symbol FFTs
|
||||
k=(n+1)*kstep;
|
||||
jt9com_.npts8=k/8;
|
||||
dataSink(k);
|
||||
dataSink(k * sizeof (jt9com_.d2[0]));
|
||||
if(n%10 == 1 or n == m_hsymStop)
|
||||
qApp->processEvents(); //Keep GUI responsive
|
||||
}
|
||||
@ -1718,7 +1733,7 @@ void MainWindow::guiUpdate()
|
||||
}
|
||||
if(!bTxTime || m_btxMute) {
|
||||
m_btxok=false;
|
||||
m_soundOutput.mute();
|
||||
m_modulator.mute();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1815,9 +1830,9 @@ void MainWindow::guiUpdate()
|
||||
|
||||
signalMeter->setValue(0);
|
||||
m_monitoring=false;
|
||||
m_soundInput.setMonitoring(false);
|
||||
m_detector.setMonitoring(false);
|
||||
m_btxok=true;
|
||||
m_soundOutput.mute(false);
|
||||
m_modulator.mute(false);
|
||||
m_transmitting=true;
|
||||
ui->pbTxMode->setEnabled(false);
|
||||
if(!m_tune) {
|
||||
@ -1940,12 +1955,12 @@ void MainWindow::startTx2()
|
||||
QString t=ui->tx6->text();
|
||||
double snr=t.mid(1,5).toDouble();
|
||||
if(snr>0.0 or snr < -50.0) snr=99.0;
|
||||
m_soundOutput.start(m_paOutDevice,m_modeTx,m_TRperiod,m_nsps,m_txFreq,m_bSplit || m_bXIT ? m_XIT : 0,snr);
|
||||
transmit (snr);
|
||||
signalMeter->setValue(0);
|
||||
m_monitoring=false;
|
||||
m_soundInput.setMonitoring(false);
|
||||
m_detector.setMonitoring(false);
|
||||
m_btxok=true;
|
||||
m_soundOutput.mute(false);
|
||||
m_modulator.mute(false);
|
||||
m_transmitting=true;
|
||||
ui->pbTxMode->setEnabled(false);
|
||||
}
|
||||
@ -1954,6 +1969,7 @@ void MainWindow::startTx2()
|
||||
void MainWindow::stopTx()
|
||||
{
|
||||
m_soundOutput.stop();
|
||||
m_modulator.close ();
|
||||
m_transmitting=false;
|
||||
ui->pbTxMode->setEnabled(true);
|
||||
g_iptt=0;
|
||||
@ -1961,7 +1977,7 @@ void MainWindow::stopTx()
|
||||
lab1->setText("");
|
||||
ptt0Timer->start(200); //Sequencer delay
|
||||
m_monitoring=true;
|
||||
m_soundInput.setMonitoring(true);
|
||||
m_detector.setMonitoring(true);
|
||||
}
|
||||
|
||||
void MainWindow::stopTx2()
|
||||
@ -2573,7 +2589,6 @@ void MainWindow::on_actionJT9_1_triggered()
|
||||
m_TRperiod=60;
|
||||
m_nsps=6912;
|
||||
m_hsymStop=173;
|
||||
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
||||
lab3->setStyleSheet("QLabel{background-color: #ff6ec7}");
|
||||
lab3->setText(m_mode);
|
||||
ui->actionJT9_1->setChecked(true);
|
||||
@ -2591,7 +2606,6 @@ void MainWindow::on_actionJT65_triggered()
|
||||
m_TRperiod=60;
|
||||
m_nsps=6912; //For symspec only
|
||||
m_hsymStop=173;
|
||||
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
||||
lab3->setStyleSheet("QLabel{background-color: #ffff00}");
|
||||
lab3->setText(m_mode);
|
||||
ui->actionJT65->setChecked(true);
|
||||
@ -2609,7 +2623,6 @@ void MainWindow::on_actionJT9_JT65_triggered()
|
||||
m_TRperiod=60;
|
||||
m_nsps=6912;
|
||||
m_hsymStop=173;
|
||||
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
||||
lab3->setStyleSheet("QLabel{background-color: #ffa500}");
|
||||
lab3->setText(m_mode);
|
||||
ui->actionJT9_JT65->setChecked(true);
|
||||
@ -2624,7 +2637,7 @@ void MainWindow::on_TxFreqSpinBox_valueChanged(int n)
|
||||
m_txFreq=n;
|
||||
if(g_pWideGraph!=NULL) g_pWideGraph->setTxFreq(n);
|
||||
if(m_lockTxFreq) ui->RxFreqSpinBox->setValue(n);
|
||||
m_soundOutput.setTxFreq(n);
|
||||
m_modulator.setFrequency(m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
|
||||
}
|
||||
|
||||
void MainWindow::on_RxFreqSpinBox_valueChanged(int n)
|
||||
@ -2954,7 +2967,7 @@ void MainWindow::on_tuneButton_clicked()
|
||||
} else {
|
||||
m_tune=true;
|
||||
m_sent73=false;
|
||||
m_soundOutput.tune(m_tune);
|
||||
m_modulator.tune();
|
||||
m_repeatMsg=0;
|
||||
ui->tuneButton->setStyleSheet(m_pbTune_style);
|
||||
}
|
||||
@ -2964,11 +2977,11 @@ void MainWindow::on_stopTxButton_clicked() //Stop Tx
|
||||
{
|
||||
if(m_tune) {
|
||||
m_tune=false;
|
||||
m_soundOutput.tune(m_tune);
|
||||
m_modulator.tune(m_tune);
|
||||
}
|
||||
if(m_auto) on_autoButton_clicked();
|
||||
m_btxok=false;
|
||||
m_soundOutput.mute();
|
||||
m_modulator.mute();
|
||||
m_repeatMsg=0;
|
||||
ui->tuneButton->setStyleSheet("");
|
||||
}
|
||||
@ -3024,15 +3037,20 @@ void MainWindow::rigOpen()
|
||||
} else {
|
||||
ui->readFreq->setStyleSheet("QPushButton{background-color: orange; \
|
||||
border-width: 0px; border-radius: 5px;}");
|
||||
}
|
||||
if(m_bSplit) ui->readFreq->setText("S");
|
||||
if(!m_bSplit) ui->readFreq->setText("");
|
||||
} else {
|
||||
if(m_CATerror) ui->readFreq->setStyleSheet("QPushButton{background-color: red; \
|
||||
}
|
||||
|
||||
QFont font=ui->readFreq->font();
|
||||
font.setPointSize(9);
|
||||
font.setWeight(75);
|
||||
ui->readFreq->setFont(font);
|
||||
if(m_bSplit) ui->readFreq->setText("S");
|
||||
if(!m_bSplit) ui->readFreq->setText("");
|
||||
} else {
|
||||
if(m_CATerror) ui->readFreq->setStyleSheet("QPushButton{background-color: red; \
|
||||
border-width: 0px; border-radius: 5px;}");
|
||||
if(!m_CATerror) ui->readFreq->setStyleSheet("");
|
||||
ui->readFreq->setText("");
|
||||
}
|
||||
if(!m_CATerror) ui->readFreq->setStyleSheet("");
|
||||
ui->readFreq->setText("");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAllow_multiple_instances_triggered(bool checked)
|
||||
@ -3104,8 +3122,7 @@ void MainWindow::setXIT(int n)
|
||||
ret=rig->setSplitFreq(MHz(m_dialFreq)+m_XIT,RIG_VFO_B);
|
||||
}
|
||||
}
|
||||
if(m_bSplit) m_soundOutput.setXIT(m_XIT);
|
||||
if(!m_bSplit) m_soundOutput.setXIT(0);
|
||||
m_modulator.setFrequency(m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
|
||||
}
|
||||
|
||||
void MainWindow::setFreq4(int rxFreq, int txFreq)
|
||||
@ -3151,10 +3168,29 @@ void MainWindow::pollRigFreq()
|
||||
m_catEnabled=false;
|
||||
ui->readFreq->setStyleSheet("QPushButton{background-color: red; \
|
||||
border-width: 0px; border-radius: 5px;}");
|
||||
}
|
||||
} else {
|
||||
int ndiff=1000000.0*(fMHz-m_dialFreq);
|
||||
if(ndiff!=0) dialFreqChanged2(fMHz);
|
||||
}
|
||||
} else {
|
||||
int ndiff=1000000.0*(fMHz-m_dialFreq);
|
||||
if(ndiff!=0) dialFreqChanged2(fMHz);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::transmit (double snr)
|
||||
{
|
||||
QScopedPointer<std::vector<int> > cw (new std::vector<int> (NUM_CW_SYMBOLS));
|
||||
cw->assign (icw, icw + NUM_CW_SYMBOLS); // load data
|
||||
if (m_modeTx == "JT65")
|
||||
{
|
||||
QScopedPointer<std::vector<int> > symbols (new std::vector<int> (NUM_JT65_SYMBOLS));
|
||||
symbols->assign (itone, itone + NUM_JT65_SYMBOLS); // load data
|
||||
m_modulator.open (symbols.take (), cw.take (), 4096.0 * 12000.0 / 11025.0, m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0), snr);
|
||||
}
|
||||
else
|
||||
{
|
||||
QScopedPointer<std::vector<int> > symbols (new std::vector<int> (NUM_JT65_SYMBOLS));
|
||||
symbols->assign (itone, itone + NUM_JT9_SYMBOLS); // load data
|
||||
m_modulator.open (symbols.take (), cw.take (), m_nsps, m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0), snr);
|
||||
}
|
||||
m_soundOutput.start(m_audioOutputDevice, &m_modulator);
|
||||
}
|
||||
|
15
mainwindow.h
15
mainwindow.h
@ -7,6 +7,9 @@
|
||||
#endif
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QList>
|
||||
#include <QAudioDeviceInfo>
|
||||
|
||||
#include "soundin.h"
|
||||
#include "soundout.h"
|
||||
#include "commons.h"
|
||||
@ -14,6 +17,8 @@
|
||||
#include "rigclass.h"
|
||||
#include "signalmeter.h"
|
||||
#include "logbook/logbook.h"
|
||||
#include "Detector.hpp"
|
||||
#include "Modulator.hpp"
|
||||
|
||||
#ifdef WIN32
|
||||
#include "PSKReporter.h"
|
||||
@ -37,8 +42,9 @@ public:
|
||||
|
||||
public slots:
|
||||
void showSoundInError(const QString& errorMsg);
|
||||
void showSoundOutError(const QString& errorMsg);
|
||||
void showStatusMessage(const QString& statusMsg);
|
||||
void dataSink(int k);
|
||||
void dataSink(qint64 bytes);
|
||||
void diskDat();
|
||||
void diskWriteFinished();
|
||||
void freezeDecode(int n);
|
||||
@ -191,8 +197,10 @@ private:
|
||||
qint32 m_nutc0;
|
||||
qint32 m_nrx;
|
||||
qint32 m_hsym;
|
||||
qint32 m_paInDevice;
|
||||
qint32 m_paOutDevice;
|
||||
QAudioDeviceInfo m_audioInputDevice;
|
||||
Detector m_detector;
|
||||
QAudioDeviceInfo m_audioOutputDevice;
|
||||
Modulator m_modulator;
|
||||
qint32 m_TRperiod;
|
||||
qint32 m_nsps;
|
||||
qint32 m_hsymStop;
|
||||
@ -372,6 +380,7 @@ private:
|
||||
void pollRigFreq();
|
||||
bool gridOK(QString g);
|
||||
QString baseCall(QString t);
|
||||
void transmit (double snr = 99.);
|
||||
};
|
||||
|
||||
extern void getfile(QString fname, int ntrperiod);
|
||||
|
102
meterwidget.cpp
102
meterwidget.cpp
@ -1,51 +1,51 @@
|
||||
// Simple bargraph meter
|
||||
// Implemented by Edson Pereira PY2SDR
|
||||
|
||||
#include "meterwidget.h"
|
||||
|
||||
MeterWidget::MeterWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_signal(0)
|
||||
{
|
||||
for ( int i = 0; i < 10; i++ ) {
|
||||
signalQueue.enqueue(0);
|
||||
}
|
||||
}
|
||||
|
||||
void MeterWidget::setValue(int value)
|
||||
{
|
||||
m_signal = value;
|
||||
signalQueue.enqueue(value);
|
||||
signalQueue.dequeue();
|
||||
|
||||
// Get signal peak
|
||||
int tmp = 0;
|
||||
for (int i = 0; i < signalQueue.size(); ++i) {
|
||||
if (signalQueue.at(i) > tmp)
|
||||
tmp = signalQueue.at(i);
|
||||
}
|
||||
m_sigPeak = tmp;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void MeterWidget::paintEvent( QPaintEvent * )
|
||||
{
|
||||
int pos;
|
||||
QPainter p;
|
||||
|
||||
p.begin(this);
|
||||
|
||||
// Sanitize
|
||||
m_signal = m_signal < 0 ? 0 : m_signal;
|
||||
m_signal = m_signal > 60 ? 60 : m_signal;
|
||||
|
||||
pos = m_signal * 2;
|
||||
QRect r(0, height() - pos, width(), pos );
|
||||
p.fillRect(r, QColor( 255, 150, 0 ));
|
||||
|
||||
// Draw peak hold indicator
|
||||
p.setPen(Qt::black);
|
||||
pos = m_sigPeak * 2;
|
||||
p.drawLine(0, height() - pos, 10, height() - pos);
|
||||
}
|
||||
// Simple bargraph meter
|
||||
// Implemented by Edson Pereira PY2SDR
|
||||
|
||||
#include "meterwidget.h"
|
||||
|
||||
MeterWidget::MeterWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_signal(0)
|
||||
{
|
||||
for ( int i = 0; i < 10; i++ ) {
|
||||
signalQueue.enqueue(0);
|
||||
}
|
||||
}
|
||||
|
||||
void MeterWidget::setValue(int value)
|
||||
{
|
||||
m_signal = value;
|
||||
signalQueue.enqueue(value);
|
||||
signalQueue.dequeue();
|
||||
|
||||
// Get signal peak
|
||||
int tmp = 0;
|
||||
for (int i = 0; i < signalQueue.size(); ++i) {
|
||||
if (signalQueue.at(i) > tmp)
|
||||
tmp = signalQueue.at(i);
|
||||
}
|
||||
m_sigPeak = tmp;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void MeterWidget::paintEvent( QPaintEvent * )
|
||||
{
|
||||
int pos;
|
||||
QPainter p;
|
||||
|
||||
p.begin(this);
|
||||
|
||||
// Sanitize
|
||||
m_signal = m_signal < 0 ? 0 : m_signal;
|
||||
m_signal = m_signal > 60 ? 60 : m_signal;
|
||||
|
||||
pos = m_signal * 2;
|
||||
QRect r(0, height() - pos, width(), pos );
|
||||
p.fillRect(r, QColor( 255, 150, 0 ));
|
||||
|
||||
// Draw peak hold indicator
|
||||
p.setPen(Qt::black);
|
||||
pos = m_sigPeak * 2;
|
||||
p.drawLine(0, height() - pos, 10, height() - pos);
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
#ifndef METERWIDGET_H
|
||||
#define METERWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtGui>
|
||||
#include <QQueue>
|
||||
|
||||
class MeterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MeterWidget(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void setValue(int value);
|
||||
|
||||
private:
|
||||
QQueue<int> signalQueue;
|
||||
|
||||
int m_signal;
|
||||
int m_sigPeak;
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent * );
|
||||
|
||||
};
|
||||
|
||||
#endif // METERWIDGET_H
|
||||
#ifndef METERWIDGET_H
|
||||
#define METERWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtGui>
|
||||
#include <QQueue>
|
||||
|
||||
class MeterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MeterWidget(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void setValue(int value);
|
||||
|
||||
private:
|
||||
QQueue<int> signalQueue;
|
||||
|
||||
int m_signal;
|
||||
int m_sigPeak;
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent * );
|
||||
|
||||
};
|
||||
|
||||
#endif // METERWIDGET_H
|
||||
|
224
psk_reporter.cpp
224
psk_reporter.cpp
@ -1,112 +1,112 @@
|
||||
// KISS Interface for posting spots to PSK Reporter web site
|
||||
// Implemented by Edson Pereira PY2SDR
|
||||
//
|
||||
// Reports will be sent in batch mode every 5 minutes.
|
||||
|
||||
#include "psk_reporter.h"
|
||||
|
||||
PSK_Reporter::PSK_Reporter(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_sequenceNumber(0)
|
||||
{
|
||||
m_header_h = "000Allllttttttttssssssssiiiiiiii";
|
||||
|
||||
// We use 50E2 and 50E3 for link Id
|
||||
m_rxInfoDescriptor_h = "0003002C50E200040000"
|
||||
"8002FFFF0000768F" // 2. Rx Call
|
||||
"8004FFFF0000768F" // 4. Rx Grid
|
||||
"8008FFFF0000768F" // 8. Rx Soft
|
||||
"8009FFFF0000768F" // 9. Rx Antenna
|
||||
"0000";
|
||||
|
||||
m_txInfoDescriptor_h = "0002003C50E30007"
|
||||
"8001FFFF0000768F" // 1. Tx Call
|
||||
"800500040000768F" // 5. Tx Freq
|
||||
"800600010000768F" // 6. Tx snr
|
||||
"800AFFFF0000768F" // 10. Tx Mode
|
||||
"8003FFFF0000768F" // 3. Tx Grid
|
||||
"800B00010000768F" // 11. Tx info src
|
||||
"00960004"; // Report time
|
||||
|
||||
|
||||
qsrand(QDateTime::currentDateTime().toTime_t());
|
||||
m_randomId_h = QString("%1").arg(qrand(),8,16,QChar('0'));
|
||||
|
||||
m_udpSocket = new QUdpSocket(this);
|
||||
|
||||
reportTimer = new QTimer(this);
|
||||
connect(reportTimer, SIGNAL(timeout()), this, SLOT(sendReport()));
|
||||
reportTimer->start(5*60*1000); // 5 minutes;
|
||||
}
|
||||
|
||||
void PSK_Reporter::setLocalStation(QString call, QString gridSquare, QString antenna, QString programInfo)
|
||||
{
|
||||
m_rxCall = call;
|
||||
m_rxGrid = gridSquare;
|
||||
m_rxAnt = antenna;
|
||||
m_progId = programInfo;
|
||||
//qDebug() << "PSK_Reporter::setLocalStation. Antenna:" << antenna;
|
||||
}
|
||||
|
||||
void PSK_Reporter::addRemoteStation(QString call, QString grid, QString freq, QString mode, QString snr, QString time )
|
||||
{
|
||||
QHash<QString,QString> spot;
|
||||
spot["call"] = call;
|
||||
spot["grid"] = grid;
|
||||
spot["snr"] = snr;
|
||||
spot["freq"] = freq;
|
||||
spot["mode"] = mode;
|
||||
spot["time"] = time;
|
||||
m_spotQueue.enqueue(spot);
|
||||
}
|
||||
|
||||
void PSK_Reporter::sendReport()
|
||||
{
|
||||
QString report_h;
|
||||
|
||||
// Header
|
||||
QString header_h = m_header_h;
|
||||
header_h.replace("tttttttt", QString("%1").arg(QDateTime::currentDateTime().toTime_t(),8,16,QChar('0')));
|
||||
header_h.replace("ssssssss", QString("%1").arg(++m_sequenceNumber,8,16,QChar('0')));
|
||||
header_h.replace("iiiiiiii", m_randomId_h);
|
||||
|
||||
// Receiver information
|
||||
QString rxInfoData_h = "50E2llll";
|
||||
rxInfoData_h += QString("%1").arg(m_rxCall.length(),2,16,QChar('0')) + m_rxCall.toUtf8().toHex();
|
||||
rxInfoData_h += QString("%1").arg(m_rxGrid.length(),2,16,QChar('0')) + m_rxGrid.toUtf8().toHex();
|
||||
rxInfoData_h += QString("%1").arg(m_progId.length(),2,16,QChar('0')) + m_progId.toUtf8().toHex();
|
||||
rxInfoData_h += QString("%1").arg(m_rxAnt.length(),2,16,QChar('0')) + m_rxAnt.toUtf8().toHex();
|
||||
rxInfoData_h += "0000";
|
||||
rxInfoData_h.replace("50E2llll", "50E2" + QString("%1").arg(rxInfoData_h.length()/2,4,16,QChar('0')));
|
||||
|
||||
// Sender information
|
||||
if (! m_spotQueue.isEmpty()) {
|
||||
QString txInfoData_h = "50E3llll";
|
||||
while (!m_spotQueue.isEmpty()) {
|
||||
QHash<QString,QString> spot = m_spotQueue.dequeue();
|
||||
txInfoData_h += QString("%1").arg(spot["call"].length(),2,16,QChar('0')) + spot["call"].toUtf8().toHex();
|
||||
txInfoData_h += QString("%1").arg(spot["freq"].toLongLong(),8,16,QChar('0'));
|
||||
txInfoData_h += QString("%1").arg(spot["snr"].toInt(),8,16,QChar('0')).right(2);
|
||||
txInfoData_h += QString("%1").arg(spot["mode"].length(),2,16,QChar('0')) + spot["mode"].toUtf8().toHex();
|
||||
txInfoData_h += QString("%1").arg(spot["grid"].length(),2,16,QChar('0')) + spot["grid"].toUtf8().toHex();
|
||||
txInfoData_h += QString("%1").arg(1,2,16,QChar('0')); // REPORTER_SOURCE_AUTOMATIC
|
||||
txInfoData_h += QString("%1").arg(spot["time"].toInt(),8,16,QChar('0'));
|
||||
}
|
||||
txInfoData_h += "0000";
|
||||
txInfoData_h.replace("50E3llll", "50E3" + QString("%1").arg(txInfoData_h.length()/2,4,16,QChar('0')));
|
||||
report_h = header_h + m_rxInfoDescriptor_h + m_txInfoDescriptor_h + rxInfoData_h + txInfoData_h;
|
||||
//qDebug() << "Sending Report TX: ";
|
||||
} else {
|
||||
report_h = header_h + m_rxInfoDescriptor_h + rxInfoData_h;
|
||||
//qDebug() << "Sending Report RX: ";
|
||||
}
|
||||
|
||||
report_h.replace("000Allll", "000A" + QString("%1").arg(report_h.length()/2,4,16,QChar('0')));
|
||||
QByteArray report = QByteArray::fromHex(report_h.toUtf8());
|
||||
|
||||
// Get IP address for pskreporter.info and send report via UDP
|
||||
QHostInfo info = QHostInfo::fromName("report.pskreporter.info");
|
||||
m_udpSocket->writeDatagram(report,info.addresses().at(0),4739);
|
||||
}
|
||||
|
||||
|
||||
// KISS Interface for posting spots to PSK Reporter web site
|
||||
// Implemented by Edson Pereira PY2SDR
|
||||
//
|
||||
// Reports will be sent in batch mode every 5 minutes.
|
||||
|
||||
#include "psk_reporter.h"
|
||||
|
||||
PSK_Reporter::PSK_Reporter(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_sequenceNumber(0)
|
||||
{
|
||||
m_header_h = "000Allllttttttttssssssssiiiiiiii";
|
||||
|
||||
// We use 50E2 and 50E3 for link Id
|
||||
m_rxInfoDescriptor_h = "0003002C50E200040000"
|
||||
"8002FFFF0000768F" // 2. Rx Call
|
||||
"8004FFFF0000768F" // 4. Rx Grid
|
||||
"8008FFFF0000768F" // 8. Rx Soft
|
||||
"8009FFFF0000768F" // 9. Rx Antenna
|
||||
"0000";
|
||||
|
||||
m_txInfoDescriptor_h = "0002003C50E30007"
|
||||
"8001FFFF0000768F" // 1. Tx Call
|
||||
"800500040000768F" // 5. Tx Freq
|
||||
"800600010000768F" // 6. Tx snr
|
||||
"800AFFFF0000768F" // 10. Tx Mode
|
||||
"8003FFFF0000768F" // 3. Tx Grid
|
||||
"800B00010000768F" // 11. Tx info src
|
||||
"00960004"; // Report time
|
||||
|
||||
|
||||
qsrand(QDateTime::currentDateTime().toTime_t());
|
||||
m_randomId_h = QString("%1").arg(qrand(),8,16,QChar('0'));
|
||||
|
||||
m_udpSocket = new QUdpSocket(this);
|
||||
|
||||
reportTimer = new QTimer(this);
|
||||
connect(reportTimer, SIGNAL(timeout()), this, SLOT(sendReport()));
|
||||
reportTimer->start(5*60*1000); // 5 minutes;
|
||||
}
|
||||
|
||||
void PSK_Reporter::setLocalStation(QString call, QString gridSquare, QString antenna, QString programInfo)
|
||||
{
|
||||
m_rxCall = call;
|
||||
m_rxGrid = gridSquare;
|
||||
m_rxAnt = antenna;
|
||||
m_progId = programInfo;
|
||||
//qDebug() << "PSK_Reporter::setLocalStation. Antenna:" << antenna;
|
||||
}
|
||||
|
||||
void PSK_Reporter::addRemoteStation(QString call, QString grid, QString freq, QString mode, QString snr, QString time )
|
||||
{
|
||||
QHash<QString,QString> spot;
|
||||
spot["call"] = call;
|
||||
spot["grid"] = grid;
|
||||
spot["snr"] = snr;
|
||||
spot["freq"] = freq;
|
||||
spot["mode"] = mode;
|
||||
spot["time"] = time;
|
||||
m_spotQueue.enqueue(spot);
|
||||
}
|
||||
|
||||
void PSK_Reporter::sendReport()
|
||||
{
|
||||
QString report_h;
|
||||
|
||||
// Header
|
||||
QString header_h = m_header_h;
|
||||
header_h.replace("tttttttt", QString("%1").arg(QDateTime::currentDateTime().toTime_t(),8,16,QChar('0')));
|
||||
header_h.replace("ssssssss", QString("%1").arg(++m_sequenceNumber,8,16,QChar('0')));
|
||||
header_h.replace("iiiiiiii", m_randomId_h);
|
||||
|
||||
// Receiver information
|
||||
QString rxInfoData_h = "50E2llll";
|
||||
rxInfoData_h += QString("%1").arg(m_rxCall.length(),2,16,QChar('0')) + m_rxCall.toUtf8().toHex();
|
||||
rxInfoData_h += QString("%1").arg(m_rxGrid.length(),2,16,QChar('0')) + m_rxGrid.toUtf8().toHex();
|
||||
rxInfoData_h += QString("%1").arg(m_progId.length(),2,16,QChar('0')) + m_progId.toUtf8().toHex();
|
||||
rxInfoData_h += QString("%1").arg(m_rxAnt.length(),2,16,QChar('0')) + m_rxAnt.toUtf8().toHex();
|
||||
rxInfoData_h += "0000";
|
||||
rxInfoData_h.replace("50E2llll", "50E2" + QString("%1").arg(rxInfoData_h.length()/2,4,16,QChar('0')));
|
||||
|
||||
// Sender information
|
||||
if (! m_spotQueue.isEmpty()) {
|
||||
QString txInfoData_h = "50E3llll";
|
||||
while (!m_spotQueue.isEmpty()) {
|
||||
QHash<QString,QString> spot = m_spotQueue.dequeue();
|
||||
txInfoData_h += QString("%1").arg(spot["call"].length(),2,16,QChar('0')) + spot["call"].toUtf8().toHex();
|
||||
txInfoData_h += QString("%1").arg(spot["freq"].toLongLong(),8,16,QChar('0'));
|
||||
txInfoData_h += QString("%1").arg(spot["snr"].toInt(),8,16,QChar('0')).right(2);
|
||||
txInfoData_h += QString("%1").arg(spot["mode"].length(),2,16,QChar('0')) + spot["mode"].toUtf8().toHex();
|
||||
txInfoData_h += QString("%1").arg(spot["grid"].length(),2,16,QChar('0')) + spot["grid"].toUtf8().toHex();
|
||||
txInfoData_h += QString("%1").arg(1,2,16,QChar('0')); // REPORTER_SOURCE_AUTOMATIC
|
||||
txInfoData_h += QString("%1").arg(spot["time"].toInt(),8,16,QChar('0'));
|
||||
}
|
||||
txInfoData_h += "0000";
|
||||
txInfoData_h.replace("50E3llll", "50E3" + QString("%1").arg(txInfoData_h.length()/2,4,16,QChar('0')));
|
||||
report_h = header_h + m_rxInfoDescriptor_h + m_txInfoDescriptor_h + rxInfoData_h + txInfoData_h;
|
||||
//qDebug() << "Sending Report TX: ";
|
||||
} else {
|
||||
report_h = header_h + m_rxInfoDescriptor_h + rxInfoData_h;
|
||||
//qDebug() << "Sending Report RX: ";
|
||||
}
|
||||
|
||||
report_h.replace("000Allll", "000A" + QString("%1").arg(report_h.length()/2,4,16,QChar('0')));
|
||||
QByteArray report = QByteArray::fromHex(report_h.toUtf8());
|
||||
|
||||
// Get IP address for pskreporter.info and send report via UDP
|
||||
QHostInfo info = QHostInfo::fromName("report.pskreporter.info");
|
||||
m_udpSocket->writeDatagram(report,info.addresses().at(0),4739);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,42 +1,42 @@
|
||||
#ifndef PSK_REPORTER_H
|
||||
#define PSK_REPORTER_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QUdpSocket>
|
||||
#include <QHostInfo>
|
||||
|
||||
class PSK_Reporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PSK_Reporter(QObject *parent = 0);
|
||||
void setLocalStation(QString call, QString grid, QString antenna, QString programInfo);
|
||||
void addRemoteStation(QString call, QString grid, QString freq, QString mode, QString snr, QString time);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void sendReport();
|
||||
|
||||
private:
|
||||
QString m_header_h;
|
||||
QString m_rxInfoDescriptor_h;
|
||||
QString m_txInfoDescriptor_h;
|
||||
QString m_randomId_h;
|
||||
QString m_linkId_h;
|
||||
|
||||
QString m_rxCall;
|
||||
QString m_rxGrid;
|
||||
QString m_rxAnt;
|
||||
QString m_progId;
|
||||
|
||||
QQueue< QHash<QString,QString> > m_spotQueue;
|
||||
|
||||
QUdpSocket *m_udpSocket;
|
||||
|
||||
QTimer *reportTimer;
|
||||
|
||||
int m_sequenceNumber;
|
||||
};
|
||||
|
||||
#endif // PSK_REPORTER_H
|
||||
#ifndef PSK_REPORTER_H
|
||||
#define PSK_REPORTER_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QUdpSocket>
|
||||
#include <QHostInfo>
|
||||
|
||||
class PSK_Reporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PSK_Reporter(QObject *parent = 0);
|
||||
void setLocalStation(QString call, QString grid, QString antenna, QString programInfo);
|
||||
void addRemoteStation(QString call, QString grid, QString freq, QString mode, QString snr, QString time);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void sendReport();
|
||||
|
||||
private:
|
||||
QString m_header_h;
|
||||
QString m_rxInfoDescriptor_h;
|
||||
QString m_txInfoDescriptor_h;
|
||||
QString m_randomId_h;
|
||||
QString m_linkId_h;
|
||||
|
||||
QString m_rxCall;
|
||||
QString m_rxGrid;
|
||||
QString m_rxAnt;
|
||||
QString m_progId;
|
||||
|
||||
QQueue< QHash<QString,QString> > m_spotQueue;
|
||||
|
||||
QUdpSocket *m_udpSocket;
|
||||
|
||||
QTimer *reportTimer;
|
||||
|
||||
int m_sequenceNumber;
|
||||
};
|
||||
|
||||
#endif // PSK_REPORTER_H
|
||||
|
664
rigclass.cpp
664
rigclass.cpp
@ -1,332 +1,332 @@
|
||||
/**
|
||||
* \file src/rigclass.cc
|
||||
* \brief Ham Radio Control Libraries C++ interface
|
||||
* \author Stephane Fillod
|
||||
* \date 2001-2003
|
||||
*
|
||||
* Hamlib C++ interface is a frontend implementing wrapper functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Hamlib C++ bindings - main file
|
||||
* Copyright (c) 2001-2003 by Stephane Fillod
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <hamlib/rig.h>
|
||||
#include "rigclass.h"
|
||||
#include <QDebug>
|
||||
#include <QHostAddress>
|
||||
|
||||
#define NUMTRIES 5
|
||||
|
||||
static int hamlibpp_freq_event(RIG *rig, vfo_t vfo, freq_t freq, rig_ptr_t arg);
|
||||
|
||||
static int hamlibpp_freq_event(RIG *rig, vfo_t vfo, freq_t freq, rig_ptr_t arg)
|
||||
{
|
||||
if (!rig || !rig->state.obj)
|
||||
return -RIG_EINVAL;
|
||||
|
||||
/* assert rig == ((Rig*)rig->state.obj).theRig */
|
||||
return ((Rig*)rig->state.obj)->FreqEvent(vfo, freq, arg);
|
||||
}
|
||||
|
||||
Rig::Rig()
|
||||
{
|
||||
rig_set_debug_level( RIG_DEBUG_WARN);
|
||||
}
|
||||
|
||||
Rig::~Rig() {
|
||||
theRig->state.obj = NULL;
|
||||
rig_cleanup(theRig);
|
||||
caps = NULL;
|
||||
}
|
||||
|
||||
int Rig::init(rig_model_t rig_model)
|
||||
{
|
||||
int initOk;
|
||||
|
||||
theRig = rig_init(rig_model);
|
||||
if (!theRig)
|
||||
initOk = false;
|
||||
else
|
||||
initOk = true;
|
||||
|
||||
caps = theRig->caps;
|
||||
theRig->callbacks.freq_event = &hamlibpp_freq_event;
|
||||
theRig->state.obj = (rig_ptr_t)this;
|
||||
|
||||
return initOk;
|
||||
}
|
||||
|
||||
int Rig::open(int n) {
|
||||
m_hrd=false;
|
||||
m_cmndr=false;
|
||||
if(n<9900) {
|
||||
if(n==-99999) return -1; //Silence compiler warning
|
||||
return rig_open(theRig);
|
||||
}
|
||||
|
||||
#ifdef WIN32 // Ham radio Deluxe or Commander (Windows only)
|
||||
if(n==9999) {
|
||||
m_hrd=true;
|
||||
bool bConnect=false;
|
||||
bConnect = HRDInterfaceConnect(L"localhost",7809);
|
||||
if(bConnect) {
|
||||
const wchar_t* context=HRDInterfaceSendMessage(L"Get Context");
|
||||
m_context="[" + QString::fromWCharArray (context,-1) + "] ";
|
||||
HRDInterfaceFreeString(context);
|
||||
return 0;
|
||||
} else {
|
||||
m_hrd=false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(n==9998) {
|
||||
if(commanderSocket->state()==QAbstractSocket::ConnectedState) {
|
||||
commanderSocket->abort();
|
||||
}
|
||||
|
||||
if(commanderSocket->state()==QAbstractSocket::UnconnectedState) {
|
||||
commanderSocket->connectToHost(QHostAddress::LocalHost, 52002);
|
||||
if(!commanderSocket->waitForConnected(1000)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
QString t;
|
||||
t="<command:10>CmdGetFreq<parameters:0>";
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForReadyRead(1000);
|
||||
QByteArray reply=commanderSocket->read(128);
|
||||
if(reply.indexOf("<CmdFreq:")==0) {
|
||||
m_cmndr=true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Rig::close(void) {
|
||||
#ifdef WIN32 // Ham Radio Deluxe only on Windows
|
||||
if(m_hrd) {
|
||||
HRDInterfaceDisconnect();
|
||||
return 0;
|
||||
} else if(m_cmndr) {
|
||||
commanderSocket->close();
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_close(theRig);
|
||||
}
|
||||
}
|
||||
|
||||
int Rig::setConf(const char *name, const char *val)
|
||||
{
|
||||
return rig_set_conf(theRig, tokenLookup(name), val);
|
||||
}
|
||||
|
||||
int Rig::setFreq(freq_t freq, vfo_t vfo) {
|
||||
#ifdef WIN32 // Ham Radio Deluxe (only on Windows)
|
||||
if(m_hrd) {
|
||||
QString t;
|
||||
int nhz=(int)freq;
|
||||
t=m_context + "Set Frequency-Hz " + QString::number(nhz);
|
||||
const wchar_t* cmnd = (const wchar_t*) t.utf16();
|
||||
const wchar_t* result=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (result,-1);
|
||||
HRDInterfaceFreeString(result);
|
||||
if(t2=="OK") {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
double f=0.001*freq;
|
||||
t.sprintf("<command:10>CmdSetFreq<parameters:23><xcvrfreq:10>%10.3f",f);
|
||||
QLocale locale;
|
||||
t.replace(".",locale.decimalPoint());
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForBytesWritten(1000);
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_set_freq(theRig, vfo, freq);
|
||||
}
|
||||
}
|
||||
|
||||
int Rig::setXit(shortfreq_t xit, vfo_t vfo)
|
||||
{
|
||||
return rig_set_xit(theRig, vfo, xit);
|
||||
}
|
||||
|
||||
int Rig::setVFO(vfo_t vfo)
|
||||
{
|
||||
return rig_set_vfo(theRig, vfo);
|
||||
}
|
||||
|
||||
vfo_t Rig::getVFO()
|
||||
{
|
||||
vfo_t vfo;
|
||||
rig_get_vfo(theRig, &vfo);
|
||||
return vfo;
|
||||
}
|
||||
|
||||
int Rig::setSplitFreq(freq_t tx_freq, vfo_t vfo) {
|
||||
#ifdef WIN32 // Ham Radio Deluxe only on Windows
|
||||
if(m_hrd) {
|
||||
QString t;
|
||||
int nhz=(int)tx_freq;
|
||||
t=m_context + "Set Frequency-Hz " + QString::number(nhz);
|
||||
const wchar_t* cmnd = (const wchar_t*) t.utf16();
|
||||
const wchar_t* result=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (result,-1);
|
||||
HRDInterfaceFreeString(result);
|
||||
if(t2=="OK") {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
double f=0.001*tx_freq;
|
||||
t.sprintf("<command:12>CmdSetTxFreq<parameters:23><xcvrfreq:10>%10.3f",f);
|
||||
QLocale locale;
|
||||
t.replace(".",locale.decimalPoint());
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForBytesWritten(1000);
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_set_split_freq(theRig, vfo, tx_freq);
|
||||
}
|
||||
}
|
||||
|
||||
freq_t Rig::getFreq(vfo_t vfo)
|
||||
{
|
||||
freq_t freq;
|
||||
#ifdef WIN32 // Ham Radio Deluxe (only on Windows)
|
||||
if(m_hrd) {
|
||||
const wchar_t* cmnd = (const wchar_t*) (m_context+"Get Frequency").utf16();
|
||||
const wchar_t* freqString=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (freqString,-1);
|
||||
HRDInterfaceFreeString(freqString);
|
||||
freq=t2.toDouble();
|
||||
return freq;
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
t="<command:10>CmdGetFreq<parameters:0>";
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForReadyRead(1000);
|
||||
QByteArray reply=commanderSocket->read(128);
|
||||
QString t2(reply);
|
||||
if(t2.indexOf("<CmdFreq:")==0) {
|
||||
int i1=t2.indexOf(">");
|
||||
t2=t2.mid(i1+1).replace(",","");
|
||||
freq=1000.0*t2.toDouble();
|
||||
return freq;
|
||||
} else {
|
||||
return -1.0;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
freq=-1.0;
|
||||
for(int i=0; i<NUMTRIES; i++) {
|
||||
int iret=rig_get_freq(theRig, vfo, &freq);
|
||||
if(iret==RIG_OK) break;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
}
|
||||
|
||||
int Rig::setMode(rmode_t mode, pbwidth_t width, vfo_t vfo) {
|
||||
return rig_set_mode(theRig, vfo, mode, width);
|
||||
}
|
||||
|
||||
rmode_t Rig::getMode(pbwidth_t& width, vfo_t vfo) {
|
||||
rmode_t mode;
|
||||
rig_get_mode(theRig, vfo, &mode, &width);
|
||||
return mode;
|
||||
}
|
||||
|
||||
int Rig::setPTT(ptt_t ptt, vfo_t vfo)
|
||||
{
|
||||
#ifdef WIN32 // Ham Radio Deluxe only on Windows
|
||||
if(m_hrd) {
|
||||
wchar_t* cmnd;
|
||||
|
||||
if(ptt==0) {
|
||||
cmnd = (wchar_t*) (m_context +
|
||||
"Set Button-Select TX 0").utf16();
|
||||
} else {
|
||||
cmnd = (wchar_t*) (m_context +
|
||||
"Set Button-Select TX 1").utf16();
|
||||
}
|
||||
const wchar_t* result=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (result,-1);
|
||||
HRDInterfaceFreeString(result);
|
||||
if(t2=="OK") {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
if(ptt==0) t="<command:5>CmdRX<parameters:0>";
|
||||
if(ptt>0) t="<command:5>CmdTX<parameters:0>";
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForBytesWritten(1000);
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_set_ptt(theRig, vfo, ptt);
|
||||
}
|
||||
}
|
||||
|
||||
ptt_t Rig::getPTT(vfo_t vfo)
|
||||
{
|
||||
ptt_t ptt;
|
||||
rig_get_ptt(theRig, vfo, &ptt);
|
||||
return ptt;
|
||||
}
|
||||
|
||||
token_t Rig::tokenLookup(const char *name)
|
||||
{
|
||||
return rig_token_lookup(theRig, name);
|
||||
}
|
||||
/**
|
||||
* \file src/rigclass.cc
|
||||
* \brief Ham Radio Control Libraries C++ interface
|
||||
* \author Stephane Fillod
|
||||
* \date 2001-2003
|
||||
*
|
||||
* Hamlib C++ interface is a frontend implementing wrapper functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Hamlib C++ bindings - main file
|
||||
* Copyright (c) 2001-2003 by Stephane Fillod
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <hamlib/rig.h>
|
||||
#include "rigclass.h"
|
||||
#include <QDebug>
|
||||
#include <QHostAddress>
|
||||
|
||||
#define NUMTRIES 5
|
||||
|
||||
static int hamlibpp_freq_event(RIG *rig, vfo_t vfo, freq_t freq, rig_ptr_t arg);
|
||||
|
||||
static int hamlibpp_freq_event(RIG *rig, vfo_t vfo, freq_t freq, rig_ptr_t arg)
|
||||
{
|
||||
if (!rig || !rig->state.obj)
|
||||
return -RIG_EINVAL;
|
||||
|
||||
/* assert rig == ((Rig*)rig->state.obj).theRig */
|
||||
return ((Rig*)rig->state.obj)->FreqEvent(vfo, freq, arg);
|
||||
}
|
||||
|
||||
Rig::Rig()
|
||||
{
|
||||
rig_set_debug_level( RIG_DEBUG_WARN);
|
||||
}
|
||||
|
||||
Rig::~Rig() {
|
||||
theRig->state.obj = NULL;
|
||||
rig_cleanup(theRig);
|
||||
caps = NULL;
|
||||
}
|
||||
|
||||
int Rig::init(rig_model_t rig_model)
|
||||
{
|
||||
int initOk;
|
||||
|
||||
theRig = rig_init(rig_model);
|
||||
if (!theRig)
|
||||
initOk = false;
|
||||
else
|
||||
initOk = true;
|
||||
|
||||
caps = theRig->caps;
|
||||
theRig->callbacks.freq_event = &hamlibpp_freq_event;
|
||||
theRig->state.obj = (rig_ptr_t)this;
|
||||
|
||||
return initOk;
|
||||
}
|
||||
|
||||
int Rig::open(int n) {
|
||||
m_hrd=false;
|
||||
m_cmndr=false;
|
||||
if(n<9900) {
|
||||
if(n==-99999) return -1; //Silence compiler warning
|
||||
return rig_open(theRig);
|
||||
}
|
||||
|
||||
#ifdef WIN32 // Ham radio Deluxe or Commander (Windows only)
|
||||
if(n==9999) {
|
||||
m_hrd=true;
|
||||
bool bConnect=false;
|
||||
bConnect = HRDInterfaceConnect(L"localhost",7809);
|
||||
if(bConnect) {
|
||||
const wchar_t* context=HRDInterfaceSendMessage(L"Get Context");
|
||||
m_context="[" + QString::fromWCharArray (context,-1) + "] ";
|
||||
HRDInterfaceFreeString(context);
|
||||
return 0;
|
||||
} else {
|
||||
m_hrd=false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(n==9998) {
|
||||
if(commanderSocket->state()==QAbstractSocket::ConnectedState) {
|
||||
commanderSocket->abort();
|
||||
}
|
||||
|
||||
if(commanderSocket->state()==QAbstractSocket::UnconnectedState) {
|
||||
commanderSocket->connectToHost(QHostAddress::LocalHost, 52002);
|
||||
if(!commanderSocket->waitForConnected(1000)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
QString t;
|
||||
t="<command:10>CmdGetFreq<parameters:0>";
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForReadyRead(1000);
|
||||
QByteArray reply=commanderSocket->read(128);
|
||||
if(reply.indexOf("<CmdFreq:")==0) {
|
||||
m_cmndr=true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Rig::close(void) {
|
||||
#ifdef WIN32 // Ham Radio Deluxe only on Windows
|
||||
if(m_hrd) {
|
||||
HRDInterfaceDisconnect();
|
||||
return 0;
|
||||
} else if(m_cmndr) {
|
||||
commanderSocket->close();
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_close(theRig);
|
||||
}
|
||||
}
|
||||
|
||||
int Rig::setConf(const char *name, const char *val)
|
||||
{
|
||||
return rig_set_conf(theRig, tokenLookup(name), val);
|
||||
}
|
||||
|
||||
int Rig::setFreq(freq_t freq, vfo_t vfo) {
|
||||
#ifdef WIN32 // Ham Radio Deluxe (only on Windows)
|
||||
if(m_hrd) {
|
||||
QString t;
|
||||
int nhz=(int)freq;
|
||||
t=m_context + "Set Frequency-Hz " + QString::number(nhz);
|
||||
const wchar_t* cmnd = (const wchar_t*) t.utf16();
|
||||
const wchar_t* result=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (result,-1);
|
||||
HRDInterfaceFreeString(result);
|
||||
if(t2=="OK") {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
double f=0.001*freq;
|
||||
t.sprintf("<command:10>CmdSetFreq<parameters:23><xcvrfreq:10>%10.3f",f);
|
||||
QLocale locale;
|
||||
t.replace(".",locale.decimalPoint());
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForBytesWritten(1000);
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_set_freq(theRig, vfo, freq);
|
||||
}
|
||||
}
|
||||
|
||||
int Rig::setXit(shortfreq_t xit, vfo_t vfo)
|
||||
{
|
||||
return rig_set_xit(theRig, vfo, xit);
|
||||
}
|
||||
|
||||
int Rig::setVFO(vfo_t vfo)
|
||||
{
|
||||
return rig_set_vfo(theRig, vfo);
|
||||
}
|
||||
|
||||
vfo_t Rig::getVFO()
|
||||
{
|
||||
vfo_t vfo;
|
||||
rig_get_vfo(theRig, &vfo);
|
||||
return vfo;
|
||||
}
|
||||
|
||||
int Rig::setSplitFreq(freq_t tx_freq, vfo_t vfo) {
|
||||
#ifdef WIN32 // Ham Radio Deluxe only on Windows
|
||||
if(m_hrd) {
|
||||
QString t;
|
||||
int nhz=(int)tx_freq;
|
||||
t=m_context + "Set Frequency-Hz " + QString::number(nhz);
|
||||
const wchar_t* cmnd = (const wchar_t*) t.utf16();
|
||||
const wchar_t* result=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (result,-1);
|
||||
HRDInterfaceFreeString(result);
|
||||
if(t2=="OK") {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
double f=0.001*tx_freq;
|
||||
t.sprintf("<command:12>CmdSetTxFreq<parameters:23><xcvrfreq:10>%10.3f",f);
|
||||
QLocale locale;
|
||||
t.replace(".",locale.decimalPoint());
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForBytesWritten(1000);
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_set_split_freq(theRig, vfo, tx_freq);
|
||||
}
|
||||
}
|
||||
|
||||
freq_t Rig::getFreq(vfo_t vfo)
|
||||
{
|
||||
freq_t freq;
|
||||
#ifdef WIN32 // Ham Radio Deluxe (only on Windows)
|
||||
if(m_hrd) {
|
||||
const wchar_t* cmnd = (const wchar_t*) (m_context+"Get Frequency").utf16();
|
||||
const wchar_t* freqString=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (freqString,-1);
|
||||
HRDInterfaceFreeString(freqString);
|
||||
freq=t2.toDouble();
|
||||
return freq;
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
t="<command:10>CmdGetFreq<parameters:0>";
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForReadyRead(1000);
|
||||
QByteArray reply=commanderSocket->read(128);
|
||||
QString t2(reply);
|
||||
if(t2.indexOf("<CmdFreq:")==0) {
|
||||
int i1=t2.indexOf(">");
|
||||
t2=t2.mid(i1+1).replace(",","");
|
||||
freq=1000.0*t2.toDouble();
|
||||
return freq;
|
||||
} else {
|
||||
return -1.0;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
freq=-1.0;
|
||||
for(int i=0; i<NUMTRIES; i++) {
|
||||
int iret=rig_get_freq(theRig, vfo, &freq);
|
||||
if(iret==RIG_OK) break;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
}
|
||||
|
||||
int Rig::setMode(rmode_t mode, pbwidth_t width, vfo_t vfo) {
|
||||
return rig_set_mode(theRig, vfo, mode, width);
|
||||
}
|
||||
|
||||
rmode_t Rig::getMode(pbwidth_t& width, vfo_t vfo) {
|
||||
rmode_t mode;
|
||||
rig_get_mode(theRig, vfo, &mode, &width);
|
||||
return mode;
|
||||
}
|
||||
|
||||
int Rig::setPTT(ptt_t ptt, vfo_t vfo)
|
||||
{
|
||||
#ifdef WIN32 // Ham Radio Deluxe only on Windows
|
||||
if(m_hrd) {
|
||||
wchar_t* cmnd;
|
||||
|
||||
if(ptt==0) {
|
||||
cmnd = (wchar_t*) (m_context +
|
||||
"Set Button-Select TX 0").utf16();
|
||||
} else {
|
||||
cmnd = (wchar_t*) (m_context +
|
||||
"Set Button-Select TX 1").utf16();
|
||||
}
|
||||
const wchar_t* result=HRDInterfaceSendMessage(cmnd);
|
||||
QString t2=QString::fromWCharArray (result,-1);
|
||||
HRDInterfaceFreeString(result);
|
||||
if(t2=="OK") {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if(m_cmndr) {
|
||||
QString t;
|
||||
if(ptt==0) t="<command:5>CmdRX<parameters:0>";
|
||||
if(ptt>0) t="<command:5>CmdTX<parameters:0>";
|
||||
QByteArray ba = t.toLocal8Bit();
|
||||
const char* buf=ba.data();
|
||||
commanderSocket->write(buf);
|
||||
commanderSocket->waitForBytesWritten(1000);
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return rig_set_ptt(theRig, vfo, ptt);
|
||||
}
|
||||
}
|
||||
|
||||
ptt_t Rig::getPTT(vfo_t vfo)
|
||||
{
|
||||
ptt_t ptt;
|
||||
rig_get_ptt(theRig, vfo, &ptt);
|
||||
return ptt;
|
||||
}
|
||||
|
||||
token_t Rig::tokenLookup(const char *name)
|
||||
{
|
||||
return rig_token_lookup(theRig, name);
|
||||
}
|
||||
|
196
rigclass.h
196
rigclass.h
@ -1,98 +1,98 @@
|
||||
/*
|
||||
* Hamlib C++ bindings - API header
|
||||
* Copyright (c) 2001-2002 by Stephane Fillod
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RIGCLASS_H
|
||||
#define _RIGCLASS_H 1
|
||||
|
||||
#include <hamlib/rig.h>
|
||||
#include <iostream>
|
||||
#include <QString>
|
||||
#include <QTcpSocket>
|
||||
|
||||
extern QTcpSocket* commanderSocket;
|
||||
|
||||
class BACKEND_IMPEXP Rig {
|
||||
private:
|
||||
RIG* theRig; // Global ref. to the rig
|
||||
bool m_hrd;
|
||||
bool m_cmndr;
|
||||
QString m_context;
|
||||
|
||||
|
||||
protected:
|
||||
public:
|
||||
Rig();
|
||||
virtual ~Rig();
|
||||
|
||||
const struct rig_caps *caps;
|
||||
|
||||
// Initialize rig
|
||||
int init(rig_model_t rig_model);
|
||||
|
||||
// This method open the communication port to the rig
|
||||
int open(int n);
|
||||
|
||||
// This method close the communication port to the rig
|
||||
int close(void);
|
||||
|
||||
int setConf(const char *name, const char *val);
|
||||
token_t tokenLookup(const char *name);
|
||||
|
||||
int setFreq(freq_t freq, vfo_t vfo = RIG_VFO_CURR);
|
||||
freq_t getFreq(vfo_t vfo = RIG_VFO_CURR);
|
||||
int setMode(rmode_t, pbwidth_t width = RIG_PASSBAND_NORMAL, vfo_t vfo = RIG_VFO_CURR);
|
||||
rmode_t getMode(pbwidth_t&, vfo_t vfo = RIG_VFO_CURR);
|
||||
int setVFO(vfo_t);
|
||||
vfo_t getVFO();
|
||||
int setXit(shortfreq_t xit, vfo_t vfo);
|
||||
int setSplitFreq(freq_t tx_freq, vfo_t vfo = RIG_VFO_CURR);
|
||||
int setPTT (ptt_t ptt, vfo_t vfo = RIG_VFO_CURR);
|
||||
ptt_t getPTT (vfo_t vfo = RIG_VFO_CURR);
|
||||
|
||||
// callbacks available in your derived object
|
||||
virtual int FreqEvent(vfo_t, freq_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int ModeEvent(vfo_t, rmode_t, pbwidth_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int VFOEvent(vfo_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int PTTEvent(vfo_t, ptt_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int DCDEvent(vfo_t, dcd_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
extern "C" {
|
||||
bool HRDInterfaceConnect(const wchar_t *host, const ushort);
|
||||
void HRDInterfaceDisconnect();
|
||||
bool HRDInterfaceIsConnected();
|
||||
wchar_t* HRDInterfaceSendMessage(const wchar_t *msg);
|
||||
void HRDInterfaceFreeString(const wchar_t *lstring);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _RIGCLASS_H
|
||||
/*
|
||||
* Hamlib C++ bindings - API header
|
||||
* Copyright (c) 2001-2002 by Stephane Fillod
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RIGCLASS_H
|
||||
#define _RIGCLASS_H 1
|
||||
|
||||
#include <hamlib/rig.h>
|
||||
#include <iostream>
|
||||
#include <QString>
|
||||
#include <QTcpSocket>
|
||||
|
||||
extern QTcpSocket* commanderSocket;
|
||||
|
||||
class BACKEND_IMPEXP Rig {
|
||||
private:
|
||||
RIG* theRig; // Global ref. to the rig
|
||||
bool m_hrd;
|
||||
bool m_cmndr;
|
||||
QString m_context;
|
||||
|
||||
|
||||
protected:
|
||||
public:
|
||||
Rig();
|
||||
virtual ~Rig();
|
||||
|
||||
const struct rig_caps *caps;
|
||||
|
||||
// Initialize rig
|
||||
int init(rig_model_t rig_model);
|
||||
|
||||
// This method open the communication port to the rig
|
||||
int open(int n);
|
||||
|
||||
// This method close the communication port to the rig
|
||||
int close(void);
|
||||
|
||||
int setConf(const char *name, const char *val);
|
||||
token_t tokenLookup(const char *name);
|
||||
|
||||
int setFreq(freq_t freq, vfo_t vfo = RIG_VFO_CURR);
|
||||
freq_t getFreq(vfo_t vfo = RIG_VFO_CURR);
|
||||
int setMode(rmode_t, pbwidth_t width = RIG_PASSBAND_NORMAL, vfo_t vfo = RIG_VFO_CURR);
|
||||
rmode_t getMode(pbwidth_t&, vfo_t vfo = RIG_VFO_CURR);
|
||||
int setVFO(vfo_t);
|
||||
vfo_t getVFO();
|
||||
int setXit(shortfreq_t xit, vfo_t vfo);
|
||||
int setSplitFreq(freq_t tx_freq, vfo_t vfo = RIG_VFO_CURR);
|
||||
int setPTT (ptt_t ptt, vfo_t vfo = RIG_VFO_CURR);
|
||||
ptt_t getPTT (vfo_t vfo = RIG_VFO_CURR);
|
||||
|
||||
// callbacks available in your derived object
|
||||
virtual int FreqEvent(vfo_t, freq_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int ModeEvent(vfo_t, rmode_t, pbwidth_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int VFOEvent(vfo_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int PTTEvent(vfo_t, ptt_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
virtual int DCDEvent(vfo_t, dcd_t, rig_ptr_t) const {
|
||||
return RIG_OK;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
extern "C" {
|
||||
bool HRDInterfaceConnect(const wchar_t *host, const ushort);
|
||||
void HRDInterfaceDisconnect();
|
||||
bool HRDInterfaceIsConnected();
|
||||
wchar_t* HRDInterfaceSendMessage(const wchar_t *msg);
|
||||
void HRDInterfaceFreeString(const wchar_t *lstring);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _RIGCLASS_H
|
||||
|
106
signalmeter.cpp
106
signalmeter.cpp
@ -1,53 +1,53 @@
|
||||
// Simple bargraph dB meter
|
||||
// Implemented by Edson Pereira PY2SDR
|
||||
//
|
||||
// Limits and geometry are hardcded for now.
|
||||
|
||||
#include "signalmeter.h"
|
||||
|
||||
SignalMeter::SignalMeter(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
resize(parent->size());
|
||||
|
||||
m_meter = new MeterWidget(this);
|
||||
m_meter->setGeometry(10, 10, 10, 120);
|
||||
|
||||
m_label = new QLabel(this);
|
||||
m_label->setGeometry(10, 135, 20, 20);
|
||||
|
||||
QLabel *dbLabel = new QLabel(this);
|
||||
dbLabel->setText("dB");
|
||||
dbLabel->setGeometry(30, 135, 20, 20);
|
||||
}
|
||||
|
||||
SignalMeter::~SignalMeter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SignalMeter::paintEvent( QPaintEvent * )
|
||||
{
|
||||
QPainter p;
|
||||
p.begin(this);
|
||||
p.drawLine(22, 10, 22, 130);
|
||||
|
||||
for ( int i = 0; i <= 60; i += 10 ) {
|
||||
p.drawLine(22, i*2 + 10, 25, i*2 + 10);
|
||||
}
|
||||
|
||||
for ( int i = 10; i < 60; i += 10 ) {
|
||||
p.drawText(30, i*2 + 15, QString::number(60 - i));
|
||||
}
|
||||
}
|
||||
|
||||
void SignalMeter::setValue(int value)
|
||||
{
|
||||
m_meter->setValue(value);
|
||||
m_label->setText(QString::number(value));
|
||||
}
|
||||
|
||||
void SignalMeter::resizeEvent(QResizeEvent *s)
|
||||
{
|
||||
resize(s->size());
|
||||
}
|
||||
// Simple bargraph dB meter
|
||||
// Implemented by Edson Pereira PY2SDR
|
||||
//
|
||||
// Limits and geometry are hardcded for now.
|
||||
|
||||
#include "signalmeter.h"
|
||||
|
||||
SignalMeter::SignalMeter(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
resize(parent->size());
|
||||
|
||||
m_meter = new MeterWidget(this);
|
||||
m_meter->setGeometry(10, 10, 10, 120);
|
||||
|
||||
m_label = new QLabel(this);
|
||||
m_label->setGeometry(10, 135, 20, 20);
|
||||
|
||||
QLabel *dbLabel = new QLabel(this);
|
||||
dbLabel->setText("dB");
|
||||
dbLabel->setGeometry(30, 135, 20, 20);
|
||||
}
|
||||
|
||||
SignalMeter::~SignalMeter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SignalMeter::paintEvent( QPaintEvent * )
|
||||
{
|
||||
QPainter p;
|
||||
p.begin(this);
|
||||
p.drawLine(22, 10, 22, 130);
|
||||
|
||||
for ( int i = 0; i <= 60; i += 10 ) {
|
||||
p.drawLine(22, i*2 + 10, 25, i*2 + 10);
|
||||
}
|
||||
|
||||
for ( int i = 10; i < 60; i += 10 ) {
|
||||
p.drawText(30, i*2 + 15, QString::number(60 - i));
|
||||
}
|
||||
}
|
||||
|
||||
void SignalMeter::setValue(int value)
|
||||
{
|
||||
m_meter->setValue(value);
|
||||
m_label->setText(QString::number(value));
|
||||
}
|
||||
|
||||
void SignalMeter::resizeEvent(QResizeEvent *s)
|
||||
{
|
||||
resize(s->size());
|
||||
}
|
||||
|
@ -1,32 +1,32 @@
|
||||
#ifndef SIGNALMETER_H
|
||||
#define SIGNALMETER_H
|
||||
|
||||
#include <QtGui>
|
||||
#include <QLabel>
|
||||
#include <meterwidget.h>
|
||||
|
||||
class SignalMeter : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SignalMeter(QWidget *parent = 0);
|
||||
~SignalMeter();
|
||||
|
||||
public slots:
|
||||
void setValue(int value);
|
||||
|
||||
private:
|
||||
MeterWidget *m_meter;
|
||||
|
||||
QLabel *m_label;
|
||||
|
||||
int m_signal;
|
||||
int m_sigPeak;
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent * );
|
||||
void resizeEvent(QResizeEvent *s);
|
||||
};
|
||||
|
||||
#endif // SIGNALMETER_H
|
||||
#ifndef SIGNALMETER_H
|
||||
#define SIGNALMETER_H
|
||||
|
||||
#include <QtGui>
|
||||
#include <QLabel>
|
||||
#include <meterwidget.h>
|
||||
|
||||
class SignalMeter : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SignalMeter(QWidget *parent = 0);
|
||||
~SignalMeter();
|
||||
|
||||
public slots:
|
||||
void setValue(int value);
|
||||
|
||||
private:
|
||||
MeterWidget *m_meter;
|
||||
|
||||
QLabel *m_label;
|
||||
|
||||
int m_signal;
|
||||
int m_sigPeak;
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent * );
|
||||
void resizeEvent(QResizeEvent *s);
|
||||
};
|
||||
|
||||
#endif // SIGNALMETER_H
|
||||
|
452
soundin.cpp
452
soundin.cpp
@ -1,375 +1,127 @@
|
||||
#ifndef QAUDIO_INPUT
|
||||
#include "soundin.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioFormat>
|
||||
#include <QAudioInput>
|
||||
#include <QDebug>
|
||||
|
||||
#define FRAMES_PER_BUFFER 1024
|
||||
#define NSMAX 6827
|
||||
#define NTMAX 120
|
||||
|
||||
extern "C" {
|
||||
#include <portaudio.h>
|
||||
extern struct {
|
||||
float ss[184*NSMAX]; //This is "common/jt9com/..." in fortran
|
||||
float savg[NSMAX];
|
||||
// float c0[2*NTMAX*1500];
|
||||
short int d2[NTMAX*12000];
|
||||
int nutc; //UTC as integer, HHMM
|
||||
int ndiskdat; //1 ==> data read from *.wav file
|
||||
int ntrperiod; //TR period (seconds)
|
||||
int mousefqso; //User-selected QSO freq (kHz)
|
||||
int newdat; //1 ==> new data, must do long FFT
|
||||
int npts8; //npts in c0() array
|
||||
int nfa; //Low decode limit (Hz)
|
||||
int nfb; //High decode limit (Hz)
|
||||
int ntol; //+/- decoding range around fQSO (Hz)
|
||||
int kin;
|
||||
int nzhsym;
|
||||
int nsave;
|
||||
int nagain;
|
||||
int ndepth;
|
||||
int ntxmode;
|
||||
int nmode;
|
||||
char datetime[20];
|
||||
} jt9com_;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------- a2dCallback
|
||||
int a2dCallback( const void *inputBuffer, void * /* outputBuffer */,
|
||||
unsigned long framesToProcess,
|
||||
const PaStreamCallbackTimeInfo * /* timeInfo */,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData )
|
||||
|
||||
// This routine called by the PortAudio engine when samples are available.
|
||||
// It may be called at interrupt level, so don't do anything
|
||||
// that could mess up the system like calling malloc() or free().
|
||||
|
||||
bool SoundInput::audioError () const
|
||||
{
|
||||
SoundInput::CallbackData * udata = reinterpret_cast<SoundInput::CallbackData *>(userData);
|
||||
int nbytes,k;
|
||||
bool result (true);
|
||||
|
||||
if( (statusFlags&paInputOverflow) != 0) {
|
||||
qDebug() << "Input Overflow in a2dCallback";
|
||||
}
|
||||
if(udata->bzero)
|
||||
{ //Start of a new Rx sequence
|
||||
udata->kin = 0; //Reset buffer pointer
|
||||
udata->bzero = false;
|
||||
Q_ASSERT_X (m_stream, "SoundInput", "programming error");
|
||||
if (m_stream)
|
||||
{
|
||||
switch (m_stream->error ())
|
||||
{
|
||||
case QAudio::OpenError:
|
||||
Q_EMIT error (tr ("An error opening the audio input device has occurred."));
|
||||
break;
|
||||
|
||||
case QAudio::IOError:
|
||||
Q_EMIT error (tr ("An error occurred during read from the audio input device."));
|
||||
break;
|
||||
|
||||
case QAudio::UnderrunError:
|
||||
Q_EMIT error (tr ("Audio data not being fed to the audio input device fast enough."));
|
||||
break;
|
||||
|
||||
case QAudio::FatalError:
|
||||
Q_EMIT error (tr ("Non-recoverable error, audio input device not usable at this time."));
|
||||
break;
|
||||
|
||||
case QAudio::NoError:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nbytes=2*framesToProcess; //Bytes per frame
|
||||
k=udata->kin;
|
||||
if(udata->monitoring) {
|
||||
memcpy(&jt9com_.d2[k],inputBuffer,nbytes); //Copy all samples to d2
|
||||
}
|
||||
udata->kin+=framesToProcess;
|
||||
jt9com_.kin=udata->kin; // we are the only writer to jt9com_ so no MT issue here
|
||||
|
||||
return paContinue;
|
||||
return result;
|
||||
}
|
||||
|
||||
SoundInput::SoundInput()
|
||||
: m_inStream(0),
|
||||
m_TRperiod(60),
|
||||
m_nsps(6912),
|
||||
m_monitoring(false),
|
||||
m_intervalTimer(this)
|
||||
{
|
||||
connect(&m_intervalTimer, SIGNAL(timeout()), this,SLOT(intervalNotify()));
|
||||
}
|
||||
|
||||
void SoundInput::start(qint32 device)
|
||||
bool SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, QIODevice * sink)
|
||||
{
|
||||
stop();
|
||||
|
||||
//---------------------------------------------------- Soundcard Setup
|
||||
PaError paerr;
|
||||
PaStreamParameters inParam;
|
||||
QAudioFormat format (device.preferredFormat());
|
||||
format.setChannelCount (1);
|
||||
format.setCodec ("audio/pcm");
|
||||
format.setSampleRate (12000);
|
||||
format.setSampleType (QAudioFormat::SignedInt);
|
||||
format.setSampleSize (16);
|
||||
|
||||
m_callbackData.kin = 0; //Buffer pointer
|
||||
m_callbackData.bzero = false; //Flag to request reset of kin
|
||||
m_callbackData.monitoring = m_monitoring;
|
||||
|
||||
inParam.device=device; //### Input Device Number ###
|
||||
inParam.channelCount=1; //Number of analog channels
|
||||
inParam.sampleFormat=paInt16; //Get i*2 from Portaudio
|
||||
inParam.suggestedLatency=0.05;
|
||||
inParam.hostApiSpecificStreamInfo=NULL;
|
||||
|
||||
paerr=Pa_IsFormatSupported(&inParam,NULL,12000.0);
|
||||
if(paerr<0) {
|
||||
emit error("PortAudio says requested soundcard format not supported.");
|
||||
}
|
||||
paerr=Pa_OpenStream(&m_inStream, //Input stream
|
||||
&inParam, //Input parameters
|
||||
NULL, //No output parameters
|
||||
12000.0, //Sample rate
|
||||
FRAMES_PER_BUFFER, //Frames per buffer
|
||||
// paClipOff+paDitherOff, //No clipping or dithering
|
||||
paClipOff, //No clipping
|
||||
a2dCallback, //Input callback routine
|
||||
&m_callbackData); //userdata
|
||||
paerr=Pa_StartStream(m_inStream);
|
||||
if(paerr<0) {
|
||||
emit error("Failed to start audio input stream.");
|
||||
return;
|
||||
}
|
||||
m_ntr0 = 99; // initial value higher than any expected
|
||||
m_intervalTimer.start(100);
|
||||
m_ms0 = QDateTime::currentMSecsSinceEpoch();
|
||||
m_nsps0 = 0;
|
||||
}
|
||||
|
||||
void SoundInput::intervalNotify()
|
||||
{
|
||||
m_callbackData.monitoring = m_monitoring; // update monitoring
|
||||
// status
|
||||
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch();
|
||||
ms=ms % 86400000;
|
||||
int nsec = ms/1000; // Time according to this computer
|
||||
int ntr = nsec % m_TRperiod;
|
||||
|
||||
int k=m_callbackData.kin; // get a copy of kin to mitigate the
|
||||
// potential race condition with the
|
||||
// callback handler when a buffer
|
||||
// reset is requested below
|
||||
|
||||
// Reset buffer pointer and symbol number at start of minute
|
||||
if(ntr < m_ntr0 or !m_monitoring or m_nsps!=m_nsps0) {
|
||||
m_nstep0=0;
|
||||
m_nsps0=m_nsps;
|
||||
m_callbackData.bzero = true; // request callback to reset buffer pointer
|
||||
}
|
||||
|
||||
if(m_monitoring) {
|
||||
int kstep=m_nsps/2;
|
||||
// m_step=k/kstep;
|
||||
m_step=(k-1)/kstep;
|
||||
if(m_step != m_nstep0) {
|
||||
emit readyForFFT(k-1); //Signal to compute new FFTs
|
||||
m_nstep0=m_step;
|
||||
}
|
||||
}
|
||||
m_ntr0=ntr;
|
||||
}
|
||||
|
||||
SoundInput::~SoundInput()
|
||||
{
|
||||
if (m_inStream)
|
||||
if (!format.isValid ())
|
||||
{
|
||||
Pa_CloseStream(m_inStream), m_inStream = 0;
|
||||
Q_EMIT error (tr ("Requested input audio format is not valid."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// this function lies!
|
||||
// if (!device.isFormatSupported (format))
|
||||
// {
|
||||
// Q_EMIT error (tr ("Requested input audio format is not supported on device."));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
m_stream.reset (new QAudioInput (device, format, this));
|
||||
if (audioError ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged);
|
||||
|
||||
m_stream->setBufferSize (m_stream->format ().bytesForFrames (framesPerBuffer));
|
||||
|
||||
m_stream->start (sink);
|
||||
|
||||
qDebug () << "audio input buffer size = " << m_stream->bufferSize () << " bytes\n";
|
||||
|
||||
return audioError () ? false : true;
|
||||
}
|
||||
|
||||
void SoundInput::handleStateChanged (QAudio::State newState) const
|
||||
{
|
||||
switch (newState)
|
||||
{
|
||||
case QAudio::IdleState:
|
||||
qDebug () << "SoundInput idle\n";
|
||||
Q_EMIT status (tr ("Idle"));
|
||||
break;
|
||||
|
||||
case QAudio::ActiveState:
|
||||
qDebug () << "SoundInput active\n";
|
||||
Q_EMIT status (tr ("Receiving"));
|
||||
break;
|
||||
|
||||
case QAudio::SuspendedState:
|
||||
qDebug () << "SoundInput suspended\n";
|
||||
Q_EMIT status (tr ("Suspended"));
|
||||
break;
|
||||
|
||||
case QAudio::StoppedState:
|
||||
if (audioError ())
|
||||
{
|
||||
qDebug () << "SoundInput error\n";
|
||||
Q_EMIT status (tr ("Error"));
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug () << "SoundInput stopped\n";
|
||||
Q_EMIT status (tr ("Stopped"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundInput::stop()
|
||||
{
|
||||
m_intervalTimer.stop();
|
||||
if (m_inStream)
|
||||
if (m_stream)
|
||||
{
|
||||
Pa_StopStream(m_inStream);
|
||||
Pa_CloseStream(m_inStream), m_inStream = 0;
|
||||
m_stream->stop ();
|
||||
}
|
||||
m_stream.reset ();
|
||||
}
|
||||
|
||||
#else // QAUDIO_INPUT
|
||||
|
||||
#include "soundin.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
#define FRAMES_PER_BUFFER 1024
|
||||
#define NSMAX 6827
|
||||
#define NTMAX 120
|
||||
|
||||
extern "C" {
|
||||
#include <portaudio.h>
|
||||
extern struct {
|
||||
float ss[184*NSMAX]; //This is "common/jt9com/..." in fortran
|
||||
float savg[NSMAX];
|
||||
// float c0[2*NTMAX*1500];
|
||||
short int d2[NTMAX*12000];
|
||||
int nutc; //UTC as integer, HHMM
|
||||
int ndiskdat; //1 ==> data read from *.wav file
|
||||
int ntrperiod; //TR period (seconds)
|
||||
int mousefqso; //User-selected QSO freq (kHz)
|
||||
int newdat; //1 ==> new data, must do long FFT
|
||||
int npts8; //npts in c0() array
|
||||
int nfa; //Low decode limit (Hz)
|
||||
int nfb; //High decode limit (Hz)
|
||||
int ntol; //+/- decoding range around fQSO (Hz)
|
||||
int kin;
|
||||
int nzhsym;
|
||||
int nsave;
|
||||
int nagain;
|
||||
int ndepth;
|
||||
int ntxmode;
|
||||
int nmode;
|
||||
char datetime[20];
|
||||
} jt9com_;
|
||||
}
|
||||
|
||||
QString reportAudioError(QAudio::Error audioError)
|
||||
SoundInput::~SoundInput ()
|
||||
{
|
||||
switch (audioError) {
|
||||
case QAudio::NoError: Q_ASSERT(false);
|
||||
case QAudio::OpenError: return QObject::tr(
|
||||
"An error opening the audio device has occurred.");
|
||||
case QAudio::IOError: return QObject::tr(
|
||||
"An error occurred during read/write of audio device.");
|
||||
case QAudio::UnderrunError: return QObject::tr(
|
||||
"Audio data not being fed to the audio device fast enough.");
|
||||
case QAudio::FatalError: return QObject::tr(
|
||||
"Non-recoverable error, audio device not usable at this time.");
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
return "";
|
||||
}
|
||||
|
||||
SoundInput::SoundInput()
|
||||
: m_dataSinkBusy(false),
|
||||
m_TRperiod(60),
|
||||
m_nsps(6912),
|
||||
m_monitoring(false),
|
||||
m_intervalTimer(this)
|
||||
{
|
||||
// qDebug() << "A";
|
||||
connect(&m_intervalTimer, SIGNAL(timeout()), this,SLOT(intervalNotify()));
|
||||
}
|
||||
|
||||
void SoundInput::start(qint32 device)
|
||||
{
|
||||
stop();
|
||||
|
||||
//---------------------------------------------------- Soundcard Setup
|
||||
m_callbackData.kin=0; //Buffer pointer
|
||||
m_callbackData.ncall=0; //Number of callbacks
|
||||
m_callbackData.bzero=false; //Flag to request reset of kin
|
||||
m_callbackData.monitoring=m_monitoring;
|
||||
|
||||
//### Temporary: hardwired device selection
|
||||
QAudioDeviceInfo DeviceInfo;
|
||||
QList<QAudioDeviceInfo> m_InDevices;
|
||||
QAudioDeviceInfo m_InDeviceInfo;
|
||||
m_InDevices = DeviceInfo.availableDevices(QAudio::AudioInput);
|
||||
inputDevice = m_InDevices.at(0);
|
||||
//###
|
||||
// qDebug() << "B" << m_InDevices.length() << inputDevice.deviceName();
|
||||
|
||||
const char* pcmCodec = "audio/pcm";
|
||||
QAudioFormat audioFormat = inputDevice.preferredFormat();
|
||||
audioFormat.setChannelCount(1);
|
||||
audioFormat.setCodec(pcmCodec);
|
||||
audioFormat.setSampleRate(12000);
|
||||
audioFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
audioFormat.setSampleSize(16);
|
||||
|
||||
// qDebug() << "C" << audioFormat << audioFormat.isValid();
|
||||
|
||||
if (!audioFormat.isValid()) {
|
||||
emit error(tr("Requested audio format is not available."));
|
||||
return;
|
||||
}
|
||||
|
||||
audioInput = new QAudioInput(inputDevice, audioFormat);
|
||||
// qDebug() << "D" << audioInput->error() << QAudio::NoError;
|
||||
if (audioInput->error() != QAudio::NoError) {
|
||||
emit error(reportAudioError(audioInput->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
stream = audioInput->start();
|
||||
// qDebug() << "E" << stream->errorString();
|
||||
|
||||
m_ntr0 = 99; // initial value higher than any expected
|
||||
m_nBusy = 0;
|
||||
m_intervalTimer.start(100);
|
||||
m_ms0 = QDateTime::currentMSecsSinceEpoch();
|
||||
m_nsps0 = 0;
|
||||
}
|
||||
|
||||
void SoundInput::intervalNotify()
|
||||
{
|
||||
m_callbackData.monitoring=m_monitoring;
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch();
|
||||
ms=ms % 86400000;
|
||||
int nsec = ms/1000; // Time according to this computer
|
||||
int ntr = nsec % m_TRperiod;
|
||||
static int k=0;
|
||||
|
||||
// qDebug() << "a" << ms << nsec;
|
||||
// Reset buffer pointer and symbol number at start of minute
|
||||
if(ntr < m_ntr0 or !m_monitoring or m_nsps!=m_nsps0) {
|
||||
m_nstep0=0;
|
||||
m_nsps0=m_nsps;
|
||||
m_callbackData.bzero=true;
|
||||
k=0;
|
||||
}
|
||||
// int k=m_callbackData.kin;
|
||||
|
||||
// How many new samples are available?
|
||||
const qint32 bytesReady = audioInput->bytesReady();
|
||||
// qDebug() << "b" << bytesReady;
|
||||
Q_ASSERT(bytesReady >= 0);
|
||||
Q_ASSERT(bytesReady % 2 == 0);
|
||||
if (bytesReady == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
qint32 bytesRead;
|
||||
bytesRead = stream->read((char*)&jt9com_.d2[k], bytesReady); // Get the new samples
|
||||
k += bytesRead/2;
|
||||
// qDebug() << "c" << bytesReady << bytesRead;
|
||||
Q_ASSERT(bytesRead <= bytesReady);
|
||||
if (bytesRead < 0) {
|
||||
emit error(tr("audio stream QIODevice::read returned -1."));
|
||||
return;
|
||||
}
|
||||
Q_ASSERT(bytesRead % 2 == 0);
|
||||
|
||||
if(m_monitoring) {
|
||||
int kstep=m_nsps/2;
|
||||
m_step=(k-1)/kstep;
|
||||
if(m_step != m_nstep0) {
|
||||
if(m_dataSinkBusy) {
|
||||
m_nBusy++;
|
||||
} else {
|
||||
emit readyForFFT(k-1); //Signal to compute new FFTs
|
||||
}
|
||||
m_nstep0=m_step;
|
||||
}
|
||||
}
|
||||
m_ntr0=ntr;
|
||||
}
|
||||
|
||||
SoundInput::~SoundInput()
|
||||
{
|
||||
/*
|
||||
if (m_inStream)
|
||||
{
|
||||
Pa_CloseStream(m_inStream), m_inStream = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*
|
||||
// memcpy(jt9com_.d2[k],buf0,bytesRead);
|
||||
// k+=bytesRead/2;
|
||||
for(int i=0; i<bytesRead/2; i++) {
|
||||
jt9com_.d2[k++]=buf0[i];
|
||||
}
|
||||
*/
|
||||
void SoundInput::stop()
|
||||
{
|
||||
m_intervalTimer.stop();
|
||||
/*
|
||||
if (m_inStream)
|
||||
{
|
||||
Pa_StopStream(m_inStream);
|
||||
Pa_CloseStream(m_inStream), m_inStream = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#endif // QAUDIO_INPUT
|
||||
|
147
soundin.h
147
soundin.h
@ -1,140 +1,47 @@
|
||||
#ifndef QAUDIO_INPUT
|
||||
#ifndef SOUNDIN_H
|
||||
#define SOUNDIN_H
|
||||
|
||||
#include <portaudio.h>
|
||||
#ifndef SOUNDIN_H__
|
||||
#define SOUNDIN_H__
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QString>
|
||||
#include <QScopedPointer>
|
||||
#include <QAudioInput>
|
||||
|
||||
extern "C" int a2dCallback( const void *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
|
||||
class QAudioDeviceInfo;
|
||||
class QAudioInput;
|
||||
class QIODevice;
|
||||
|
||||
// Gets audio data from soundcard and signals when a buffer of
|
||||
// specified size is available.
|
||||
// Gets audio data from sound sample source and passes it to a sink device
|
||||
class SoundInput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
SoundInput();
|
||||
~SoundInput();
|
||||
private:
|
||||
Q_DISABLE_COPY (SoundInput);
|
||||
|
||||
int mstep() const {return m_step;}
|
||||
|
||||
/* these can be called while processing samples */
|
||||
void setMonitoring(bool b) {m_monitoring = b;}
|
||||
void setPeriod(int ntrperiod, int nsps)
|
||||
public:
|
||||
SoundInput (QObject * parent = 0)
|
||||
: QObject (parent)
|
||||
{
|
||||
m_TRperiod=ntrperiod;
|
||||
m_nsps=nsps;
|
||||
}
|
||||
|
||||
signals:
|
||||
void readyForFFT(int k);
|
||||
void error(const QString& message);
|
||||
void status(const QString& message);
|
||||
~SoundInput ();
|
||||
|
||||
public slots:
|
||||
void start(qint32 device);
|
||||
Q_SIGNALS:
|
||||
void error (QString message) const;
|
||||
void status (QString message) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
// sink must exist from the start call to any following stop () call
|
||||
bool start(QAudioDeviceInfo const&, int framesPerBuffer, QIODevice * sink);
|
||||
void stop();
|
||||
|
||||
private:
|
||||
PaStream * m_inStream;
|
||||
qint32 m_step;
|
||||
qint32 m_TRperiod;
|
||||
qint32 m_TRperiod0;
|
||||
qint32 m_nsps;
|
||||
bool m_monitoring;
|
||||
qint64 m_ms0;
|
||||
int m_ntr0;
|
||||
int m_nstep0;
|
||||
int m_nsps0;
|
||||
bool audioError () const;
|
||||
|
||||
QTimer m_intervalTimer;
|
||||
QScopedPointer<QAudioInput> m_stream;
|
||||
|
||||
struct CallbackData
|
||||
{
|
||||
//Parameters sent to/from the portaudio callback function
|
||||
int volatile kin;
|
||||
bool volatile bzero;
|
||||
bool volatile monitoring;
|
||||
} m_callbackData;
|
||||
|
||||
private slots:
|
||||
void intervalNotify();
|
||||
|
||||
friend int a2dCallback(void const *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
|
||||
private Q_SLOTS:
|
||||
void handleStateChanged (QAudio::State) const;
|
||||
};
|
||||
|
||||
#endif // SOUNDIN_H
|
||||
|
||||
#else // QAUDIO_INPUT
|
||||
#ifndef SOUNDIN_H
|
||||
#define SOUNDIN_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioInput>
|
||||
|
||||
// Gets audio data from soundcard and signals when a buffer of
|
||||
// specified size is available.
|
||||
class SoundInput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SoundInput();
|
||||
~SoundInput();
|
||||
|
||||
void setMonitoring(bool b) {m_monitoring = b;}
|
||||
void setPeriod(int ntrperiod, int nsps) /* this can be called while processing samples */
|
||||
{
|
||||
m_TRperiod=ntrperiod;
|
||||
m_nsps=nsps;
|
||||
}
|
||||
int mstep() const {return m_step;}
|
||||
double samFacIn() const {return m_SamFacIn;}
|
||||
|
||||
signals:
|
||||
void readyForFFT(int k);
|
||||
void error(const QString& message);
|
||||
void status(const QString& message);
|
||||
|
||||
public slots:
|
||||
void start(qint32 device);
|
||||
void stop();
|
||||
|
||||
private:
|
||||
bool m_dataSinkBusy;
|
||||
double m_SamFacIn; //(Input sample rate)/12000.0
|
||||
qint32 m_step;
|
||||
qint32 m_TRperiod;
|
||||
qint32 m_TRperiod0;
|
||||
qint32 m_nsps;
|
||||
bool m_monitoring;
|
||||
qint64 m_ms0;
|
||||
int m_ntr0;
|
||||
int m_nBusy;
|
||||
int m_nstep0;
|
||||
int m_nsps0;
|
||||
|
||||
QTimer m_intervalTimer;
|
||||
QAudioDeviceInfo inputDevice; // audioinput device name
|
||||
QAudioInput* audioInput;
|
||||
QIODevice* stream;
|
||||
|
||||
struct CallbackData
|
||||
{
|
||||
int kin;
|
||||
int ncall;
|
||||
bool bzero;
|
||||
bool monitoring;
|
||||
} m_callbackData; //Parameters sent to/from the Notify function
|
||||
|
||||
private slots:
|
||||
void intervalNotify();
|
||||
};
|
||||
#endif // SOUNDIN_H
|
||||
#endif // QAUDIO_INPUT
|
||||
#endif
|
||||
|
267
soundout.cpp
267
soundout.cpp
@ -1,217 +1,112 @@
|
||||
#include "soundout.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioOutput>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
//#define FRAMES_PER_BUFFER 1024
|
||||
|
||||
extern float gran(); //Noise generator (for tests only)
|
||||
extern int itone[126]; //Audio tones for all Tx symbols
|
||||
extern int icw[250]; //Dits for CW ID
|
||||
extern int outBufSize;
|
||||
|
||||
|
||||
//--------------------------------------------------------------- d2aCallback
|
||||
int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesToProcess,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData )
|
||||
bool SoundOutput::audioError () const
|
||||
{
|
||||
SoundOutput::CallbackData * udata = reinterpret_cast<SoundOutput::CallbackData *>(userData);
|
||||
short * wptr = reinterpret_cast<short *>(outputBuffer);
|
||||
bool result (true);
|
||||
|
||||
static double twopi=2.0*3.141592653589793238462;
|
||||
static double baud;
|
||||
static double phi=0.0;
|
||||
static double dphi;
|
||||
static double freq;
|
||||
static double snr;
|
||||
static double fac;
|
||||
static double amp;
|
||||
static int ic=0,j=0;
|
||||
static int isym0=-999;
|
||||
static short int i2;
|
||||
int isym,nspd;
|
||||
Q_ASSERT_X (m_stream, "SoundOutput", "programming error");
|
||||
if (m_stream)
|
||||
{
|
||||
switch (m_stream->error ())
|
||||
{
|
||||
case QAudio::OpenError:
|
||||
Q_EMIT error (tr ("An error opening the audio output device has occurred."));
|
||||
break;
|
||||
|
||||
udata->ncall++;
|
||||
if(udata->bRestart) {
|
||||
// Time according to this computer
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
int mstr = ms % (1000*udata->ntrperiod );
|
||||
if(mstr<1000)
|
||||
{
|
||||
std::memset(wptr, 0, framesToProcess * sizeof(*wptr)); // output silence
|
||||
return paContinue;
|
||||
}
|
||||
ic=(mstr-1000)*48;
|
||||
udata->bRestart=false;
|
||||
srand(mstr); //Initialize random seed
|
||||
}
|
||||
isym=ic/(4.0*udata->dnsps); //Actual fsample=48000
|
||||
if(udata->tune) isym=0; //If tuning, send pure tone
|
||||
if(udata->txsnrdb < 0.0) {
|
||||
snr=std::pow(10.0,0.05*(udata->txsnrdb-6.0));
|
||||
fac=3000.0;
|
||||
if(snr>1.0) fac=3000.0/snr;
|
||||
}
|
||||
case QAudio::IOError:
|
||||
Q_EMIT error (tr ("An error occurred during write to the audio output device."));
|
||||
break;
|
||||
|
||||
if(isym>=udata->nsym and icw[0]>0) { //Output the CW ID
|
||||
freq=udata->ntxfreq - udata->xit;
|
||||
dphi=twopi*freq/48000.0;
|
||||
case QAudio::UnderrunError:
|
||||
Q_EMIT error (tr ("Audio data not being fed to the audio output device fast enough."));
|
||||
break;
|
||||
|
||||
// float wpm=20.0;
|
||||
// int nspd=1.2*48000.0/wpm;
|
||||
// nspd=3072; //18.75 WPM
|
||||
nspd=2048 + 512; //22.5 WPM
|
||||
int ic0=udata->nsym*4*udata->dnsps;
|
||||
for(uint i=0 ; i<framesToProcess; i++ ) {
|
||||
phi += dphi;
|
||||
if(phi>twopi) phi -= twopi;
|
||||
i2=32767.0*std::sin(phi);
|
||||
j=(ic-ic0)/nspd + 1;
|
||||
if(icw[j]==0) i2=0;
|
||||
if(udata->txsnrdb < 0.0) {
|
||||
int i4=fac*(gran() + i2*snr/32768.0);
|
||||
if(i4>32767) i4=32767;
|
||||
if(i4<-32767) i4=-32767;
|
||||
i2=i4;
|
||||
}
|
||||
if(udata->mute) i2=0;
|
||||
*wptr++ = i2; //left
|
||||
#ifdef UNIX
|
||||
*wptr++ = i2; //right
|
||||
#endif
|
||||
ic++;
|
||||
case QAudio::FatalError:
|
||||
Q_EMIT error (tr ("Non-recoverable error, audio output device not usable at this time."));
|
||||
break;
|
||||
|
||||
case QAudio::NoError:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(j>icw[0]) return paComplete;
|
||||
if(statusFlags==999999 and timeInfo==NULL and
|
||||
inputBuffer==NULL) return paContinue; //Silence compiler warning:
|
||||
return paContinue;
|
||||
}
|
||||
|
||||
baud=12000.0/udata->dnsps;
|
||||
amp=32767.0;
|
||||
int i0=(udata->nsym-0.017)*4.0*udata->dnsps;
|
||||
int i1=udata->nsym*4.0*udata->dnsps;
|
||||
bool tune = udata->tune;
|
||||
if(tune) { //If tuning, no ramp down
|
||||
i0=999*udata->dnsps;
|
||||
i1=i0;
|
||||
}
|
||||
for(uint i=0 ; i<framesToProcess; i++ ) {
|
||||
isym=ic/(4.0*udata->dnsps); //Actual fsample=48000
|
||||
if(tune) isym=0; //If tuning, send pure tone
|
||||
if(isym!=isym0) {
|
||||
freq=udata->ntxfreq + itone[isym]*baud - udata->xit;
|
||||
dphi=twopi*freq/48000.0;
|
||||
isym0=isym;
|
||||
}
|
||||
phi += dphi;
|
||||
if(phi>twopi) phi -= twopi;
|
||||
if(ic>i0) amp=0.98*amp;
|
||||
if(ic>i1) amp=0.0;
|
||||
i2=amp*std::sin(phi);
|
||||
if(udata->txsnrdb < 0.0) {
|
||||
int i4=fac*(gran() + i2*snr/32768.0);
|
||||
if(i4>32767) i4=32767;
|
||||
if(i4<-32767) i4=-32767;
|
||||
i2=i4;
|
||||
}
|
||||
if(udata->mute) i2=0;
|
||||
*wptr++ = i2; //left
|
||||
#ifdef UNIX
|
||||
*wptr++ = i2; //right
|
||||
#endif
|
||||
ic++;
|
||||
}
|
||||
if(amp==0.0) {
|
||||
if(icw[0]==0) return paComplete;
|
||||
phi=0.0;
|
||||
}
|
||||
return paContinue;
|
||||
return result;
|
||||
}
|
||||
|
||||
SoundOutput::SoundOutput()
|
||||
: m_stream(0)
|
||||
, m_outputLatency(0.)
|
||||
, m_active(false)
|
||||
bool SoundOutput::start(QAudioDeviceInfo const& device, QIODevice * source)
|
||||
{
|
||||
}
|
||||
Q_ASSERT (source);
|
||||
|
||||
void SoundOutput::start(qint32 deviceNumber,QString const& mode,int TRPeriod
|
||||
,int nsps,int txFreq,int xit,double txsnrdb)
|
||||
{
|
||||
stop();
|
||||
|
||||
PaStreamParameters outParam;
|
||||
QAudioFormat format (device.preferredFormat());
|
||||
format.setChannelCount (1);
|
||||
format.setCodec ("audio/pcm");
|
||||
format.setSampleRate (48000);
|
||||
format.setSampleType (QAudioFormat::SignedInt);
|
||||
format.setSampleSize (16);
|
||||
if (!format.isValid ())
|
||||
{
|
||||
Q_EMIT error (tr ("Requested output audio format is not valid."));
|
||||
return false;
|
||||
}
|
||||
if (!device.isFormatSupported (format))
|
||||
{
|
||||
Q_EMIT error (tr ("Requested output audio format is not supported on device."));
|
||||
return false;
|
||||
}
|
||||
|
||||
outParam.device=deviceNumber; //Output device number
|
||||
outParam.channelCount=1; //Number of analog channels
|
||||
#ifdef UNIX
|
||||
outParam.channelCount=2; //Number of analog channels
|
||||
#endif
|
||||
outParam.sampleFormat=paInt16; //Send short ints to PortAudio
|
||||
outParam.suggestedLatency=0.05;
|
||||
outParam.hostApiSpecificStreamInfo=NULL;
|
||||
m_stream.reset (new QAudioOutput (device, format, this));
|
||||
if (audioError ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged);
|
||||
|
||||
PaError paerr = Pa_IsFormatSupported(NULL,&outParam,48000.0);
|
||||
if(paerr<0) {
|
||||
qDebug() << "PortAudio says requested output format not supported.";
|
||||
qDebug() << paerr << deviceNumber;
|
||||
return;
|
||||
}
|
||||
m_stream->start (source);
|
||||
if (audioError ()) // start the input stream
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_callbackData.txsnrdb=txsnrdb;
|
||||
m_callbackData.dnsps=nsps;
|
||||
m_callbackData.nsym=85;
|
||||
if(mode=="JT65") {
|
||||
m_callbackData.dnsps=4096.0*12000.0/11025.0;
|
||||
m_callbackData.nsym=126;
|
||||
}
|
||||
m_callbackData.ntrperiod=TRPeriod;
|
||||
m_callbackData.ntxfreq=txFreq;
|
||||
m_callbackData.xit=xit;
|
||||
m_callbackData.ncall=0;
|
||||
m_callbackData.bRestart=true;
|
||||
|
||||
paerr=Pa_OpenStream(&m_stream, //Output stream
|
||||
NULL, //No input parameters
|
||||
&outParam, //Output parameters
|
||||
48000.0, //Sample rate
|
||||
outBufSize, //Frames per buffer
|
||||
paClipOff, //No clipping
|
||||
d2aCallback, //output callbeck routine
|
||||
&m_callbackData); //userdata
|
||||
|
||||
paerr=Pa_StartStream(m_stream);
|
||||
if(paerr<0) {
|
||||
qDebug() << "Failed to start audio output stream.";
|
||||
return;
|
||||
}
|
||||
const PaStreamInfo* p=Pa_GetStreamInfo(m_stream);
|
||||
m_outputLatency = p->outputLatency;
|
||||
m_ms0 = QDateTime::currentMSecsSinceEpoch();
|
||||
m_active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundOutput::handleStateChanged (QAudio::State newState) const
|
||||
{
|
||||
switch (newState)
|
||||
{
|
||||
case QAudio::IdleState: Q_EMIT status (tr ("Idle")); break;
|
||||
case QAudio::ActiveState: Q_EMIT status (tr ("Sending")); break;
|
||||
case QAudio::SuspendedState: Q_EMIT status (tr ("Suspended")); break;
|
||||
|
||||
case QAudio::StoppedState:
|
||||
if (audioError ())
|
||||
{
|
||||
Q_EMIT status (tr ("Error"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_EMIT status (tr ("Stopped"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundOutput::stop()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
Pa_StopStream(m_stream);
|
||||
Pa_CloseStream(m_stream), m_stream = 0;
|
||||
}
|
||||
m_stream.reset ();
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
SoundOutput::~SoundOutput()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
Pa_CloseStream(m_stream), m_stream = 0;
|
||||
}
|
||||
stop ();
|
||||
}
|
||||
|
78
soundout.h
78
soundout.h
@ -1,76 +1,52 @@
|
||||
#ifndef SOUNDOUT_H
|
||||
#define SOUNDOUT_H
|
||||
|
||||
#include <portaudio.h>
|
||||
#ifndef SOUNDOUT_H__
|
||||
#define SOUNDOUT_H__
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QAudioOutput>
|
||||
|
||||
extern "C" int d2aCallback(const void *, void *,
|
||||
unsigned long,
|
||||
PaStreamCallbackTimeInfo const *,
|
||||
PaStreamCallbackFlags,
|
||||
void *);
|
||||
#include "Modulator.hpp"
|
||||
|
||||
class QAudioDeviceInfo;
|
||||
|
||||
// An instance of this sends audio data to a specified soundcard.
|
||||
// Output can be muted while underway, preserving waveform timing when
|
||||
// transmission is resumed.
|
||||
|
||||
class SoundOutput : public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
Q_PROPERTY(bool running READ isRunning);
|
||||
Q_PROPERTY(bool mute READ isMuted WRITE mute);
|
||||
Q_PROPERTY(bool tune READ isTuning WRITE tune);
|
||||
|
||||
public:
|
||||
SoundOutput();
|
||||
~SoundOutput();
|
||||
private:
|
||||
Q_DISABLE_COPY (SoundOutput);
|
||||
|
||||
public:
|
||||
SoundOutput ()
|
||||
: m_active(false)
|
||||
{
|
||||
}
|
||||
~SoundOutput ();
|
||||
|
||||
bool isRunning() const {return m_active;}
|
||||
bool isMuted() const {return m_callbackData.mute;}
|
||||
bool isTuning() const {return m_callbackData.tune;}
|
||||
double outputLatency() const {return m_outputLatency;}
|
||||
|
||||
// the following can be called while the stream is running
|
||||
void setTxFreq(int n) {m_callbackData.ntxfreq = n;}
|
||||
void setXIT(int n) {m_callbackData.xit = n;}
|
||||
void mute(bool b = true) {m_callbackData.mute = b;}
|
||||
void tune(bool b = true) {m_callbackData.tune = b;}
|
||||
|
||||
public slots:
|
||||
void start(qint32 deviceNumber, QString const& mode,int TRPeriod,int nsps,int txFreq,int xit,double txsnrdb = 99.);
|
||||
public Q_SLOTS:
|
||||
bool start(QAudioDeviceInfo const& device, QIODevice * source);
|
||||
void stop();
|
||||
|
||||
// Private members
|
||||
Q_SIGNALS:
|
||||
void error (QString message) const;
|
||||
void status (QString message) const;
|
||||
|
||||
private:
|
||||
PaStream * m_stream;
|
||||
PaTime m_outputLatency;
|
||||
bool audioError () const;
|
||||
|
||||
struct CallbackData
|
||||
{
|
||||
//Parameters sent to or received from callback function
|
||||
double volatile txsnrdb;
|
||||
double volatile dnsps; //Samples per symbol (at 12000 Hz)
|
||||
int volatile ntrperiod; //T/R period (s)
|
||||
int volatile ntxfreq;
|
||||
int volatile xit;
|
||||
int volatile ncall;
|
||||
int volatile nsym;
|
||||
bool volatile mute;
|
||||
bool volatile bRestart;
|
||||
bool volatile tune;
|
||||
} m_callbackData;
|
||||
private Q_SLOTS:
|
||||
void handleStateChanged (QAudio::State) const;
|
||||
|
||||
private:
|
||||
QScopedPointer<QAudioOutput> m_stream;
|
||||
|
||||
qint64 m_ms0;
|
||||
bool m_active;
|
||||
|
||||
friend int d2aCallback(const void *, void *,
|
||||
unsigned long,
|
||||
PaStreamCallbackTimeInfo const *,
|
||||
PaStreamCallbackFlags,
|
||||
void *);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
47
wsjtx.pro
47
wsjtx.pro
@ -4,7 +4,7 @@
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui network multimedia
|
||||
QT += network multimedia
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
CONFIG += thread
|
||||
#CONFIG += console
|
||||
@ -16,7 +16,6 @@ VERSION = 1.1
|
||||
TEMPLATE = app
|
||||
#DEFINES = QT4
|
||||
DEFINES = QT5
|
||||
#DEFINES += QAUDIO_INPUT
|
||||
|
||||
win32 {
|
||||
DEFINES += WIN32
|
||||
@ -36,16 +35,31 @@ gfortran.input = F90_SOURCES
|
||||
QMAKE_EXTRA_COMPILERS += gfortran
|
||||
}
|
||||
|
||||
SOURCES += main.cpp mainwindow.cpp plotter.cpp about.cpp \
|
||||
soundin.cpp soundout.cpp devsetup.cpp widegraph.cpp \
|
||||
getfile.cpp displaytext.cpp getdev.cpp logqso.cpp \
|
||||
psk_reporter.cpp rigclass.cpp \
|
||||
signalmeter.cpp \
|
||||
meterwidget.cpp \
|
||||
logbook/logbook.cpp \
|
||||
logbook/countrydat.cpp \
|
||||
logbook/countriesworked.cpp \
|
||||
logbook/adif.cpp
|
||||
#
|
||||
# Order matters here as the link is in this order so referrers need to be after referred
|
||||
#
|
||||
SOURCES += \
|
||||
logbook/adif.cpp \
|
||||
logbook/countrydat.cpp \
|
||||
logbook/countriesworked.cpp \
|
||||
logbook/logbook.cpp \
|
||||
rigclass.cpp \
|
||||
psk_reporter.cpp \
|
||||
Modulator.cpp \
|
||||
Detector.cpp \
|
||||
logqso.cpp \
|
||||
displaytext.cpp \
|
||||
getfile.cpp \
|
||||
soundout.cpp \
|
||||
soundin.cpp \
|
||||
meterwidget.cpp \
|
||||
signalmeter.cpp \
|
||||
plotter.cpp \
|
||||
widegraph.cpp \
|
||||
devsetup.cpp \
|
||||
about.cpp \
|
||||
mainwindow.cpp \
|
||||
main.cpp
|
||||
|
||||
win32 {
|
||||
SOURCES += killbyname.cpp
|
||||
@ -54,7 +68,7 @@ SOURCES += killbyname.cpp
|
||||
HEADERS += mainwindow.h plotter.h soundin.h soundout.h \
|
||||
about.h devsetup.h widegraph.h getfile.h \
|
||||
commons.h sleep.h displaytext.h logqso.h \
|
||||
psk_reporter.h rigclass.h \
|
||||
Detector.hpp Modulator.hpp psk_reporter.h rigclass.h \
|
||||
signalmeter.h \
|
||||
meterwidget.h \
|
||||
logbook/logbook.h \
|
||||
@ -62,9 +76,6 @@ HEADERS += mainwindow.h plotter.h soundin.h soundout.h \
|
||||
logbook/countriesworked.h \
|
||||
logbook/adif.h
|
||||
|
||||
# (Is the following really needed???)
|
||||
#DEFINES += __cplusplus
|
||||
|
||||
FORMS += mainwindow.ui about.ui devsetup.ui widegraph.ui \
|
||||
logqso.ui
|
||||
|
||||
@ -73,7 +84,7 @@ RC_FILE = wsjtx.rc
|
||||
unix {
|
||||
LIBS += ../wsjtx/lib/libjt9.a
|
||||
LIBS += -lhamlib
|
||||
LIBS += -lportaudio -lgfortran -lfftw3f
|
||||
LIBS += -lgfortran -lfftw3f
|
||||
}
|
||||
|
||||
win32 {
|
||||
@ -84,8 +95,6 @@ LIBS += ../wsjtx/lib/libjt9.a
|
||||
LIBS += ../wsjtx/libfftw3f_win.a
|
||||
LIBS += ../wsjtx/libpskreporter.a
|
||||
LIBS += ../wsjtx/libHRDInterface001.a
|
||||
#LIBS += ../QtSupport/palir-02.dll
|
||||
LIBS += /users/joe/wsjt/QtSupport/palir-02.dll
|
||||
LIBS += libwsock32
|
||||
LIBS += C:/MinGW/lib/libf95.a
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user