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:
Joe Taylor 2013-08-05 13:57:55 +00:00
parent e9f9180088
commit 61f023ddd1
21 changed files with 1227 additions and 1709 deletions

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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
View File

@ -0,0 +1,5 @@
/* usleep(3) */
void usleep_(unsigned long *microsec)
{
usleep(*microsec);
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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 ();
}

View File

@ -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

View File

@ -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