mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-25 21:58:38 -05:00
Thanks to G4WJS: SoundOut functions have been moved into the GUI thread.
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3517 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
c0e80753f2
commit
9fa4270b57
107
mainwindow.cpp
107
mainwindow.cpp
@ -23,9 +23,6 @@ qint32 g_COMportOpen;
|
|||||||
qint32 g_iptt;
|
qint32 g_iptt;
|
||||||
static int nc1=1;
|
static int nc1=1;
|
||||||
wchar_t buffer[256];
|
wchar_t buffer[256];
|
||||||
bool btxok; //True if OK to transmit
|
|
||||||
bool btxMute;
|
|
||||||
double outputLatency; //Latency in seconds
|
|
||||||
|
|
||||||
|
|
||||||
WideGraph* g_pWideGraph = NULL;
|
WideGraph* g_pWideGraph = NULL;
|
||||||
@ -149,8 +146,9 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
|
|||||||
m_auto=false;
|
m_auto=false;
|
||||||
m_waterfallAvg = 1;
|
m_waterfallAvg = 1;
|
||||||
m_txFirst=false;
|
m_txFirst=false;
|
||||||
btxMute=false;
|
m_soundOutput.mute(false);
|
||||||
btxok=false;
|
m_btxMute=false;
|
||||||
|
m_btxok=false;
|
||||||
m_restart=false;
|
m_restart=false;
|
||||||
m_transmitting=false;
|
m_transmitting=false;
|
||||||
m_killAll=false;
|
m_killAll=false;
|
||||||
@ -304,9 +302,8 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
|
|||||||
connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished()));
|
connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished()));
|
||||||
|
|
||||||
m_soundInput.start(m_paInDevice);
|
m_soundInput.start(m_paInDevice);
|
||||||
soundOutThread.setOutputDevice(m_paOutDevice);
|
m_soundOutput.setTxFreq(m_txFreq);
|
||||||
soundOutThread.setTxFreq(m_txFreq);
|
m_soundOutput.tune(false);
|
||||||
soundOutThread.setTune(false);
|
|
||||||
m_monitoring=!m_monitorStartOFF; // Start with Monitoring ON/OFF
|
m_monitoring=!m_monitorStartOFF; // Start with Monitoring ON/OFF
|
||||||
m_soundInput.setMonitoring(m_monitoring);
|
m_soundInput.setMonitoring(m_monitoring);
|
||||||
m_diskData=false;
|
m_diskData=false;
|
||||||
@ -375,10 +372,7 @@ MainWindow::MainWindow(QSharedMemory *shdmem, QString *thekey, \
|
|||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
{
|
{
|
||||||
writeSettings();
|
writeSettings();
|
||||||
if (soundOutThread.isRunning()) {
|
m_soundOutput.stop();
|
||||||
soundOutThread.quitExecution=true;
|
|
||||||
soundOutThread.wait(3000);
|
|
||||||
}
|
|
||||||
if(!m_decoderBusy) {
|
if(!m_decoderBusy) {
|
||||||
QFile lockFile(m_appDir + "/.lock");
|
QFile lockFile(m_appDir + "/.lock");
|
||||||
lockFile.remove();
|
lockFile.remove();
|
||||||
@ -489,6 +483,7 @@ void MainWindow::writeSettings()
|
|||||||
settings.setValue("Fmin",m_fMin);
|
settings.setValue("Fmin",m_fMin);
|
||||||
settings.setValue("TxSplit",m_bSplit);
|
settings.setValue("TxSplit",m_bSplit);
|
||||||
settings.setValue("UseXIT",m_bXIT);
|
settings.setValue("UseXIT",m_bXIT);
|
||||||
|
settings.setValue("XIT",m_XIT);
|
||||||
settings.setValue("Plus2kHz",m_plus2kHz);
|
settings.setValue("Plus2kHz",m_plus2kHz);
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
@ -570,7 +565,7 @@ void MainWindow::readSettings()
|
|||||||
ui->RxFreqSpinBox->setValue(m_rxFreq);
|
ui->RxFreqSpinBox->setValue(m_rxFreq);
|
||||||
m_txFreq=settings.value("TxFreq",1500).toInt();
|
m_txFreq=settings.value("TxFreq",1500).toInt();
|
||||||
ui->TxFreqSpinBox->setValue(m_txFreq);
|
ui->TxFreqSpinBox->setValue(m_txFreq);
|
||||||
soundOutThread.setTxFreq(m_txFreq);
|
m_soundOutput.setTxFreq(m_txFreq);
|
||||||
m_saveDecoded=ui->actionSave_decoded->isChecked();
|
m_saveDecoded=ui->actionSave_decoded->isChecked();
|
||||||
m_saveAll=ui->actionSave_all->isChecked();
|
m_saveAll=ui->actionSave_all->isChecked();
|
||||||
m_ndepth=settings.value("NDepth",3).toInt();
|
m_ndepth=settings.value("NDepth",3).toInt();
|
||||||
@ -642,7 +637,8 @@ void MainWindow::readSettings()
|
|||||||
m_logComments=settings.value("LogComments","").toString();
|
m_logComments=settings.value("LogComments","").toString();
|
||||||
m_fMin=settings.value("fMin",2500).toInt();
|
m_fMin=settings.value("fMin",2500).toInt();
|
||||||
m_bSplit=settings.value("TxSplit",false).toBool();
|
m_bSplit=settings.value("TxSplit",false).toBool();
|
||||||
m_bXIT=settings.value("UseXit",false).toBool();
|
m_bXIT=settings.value("UseXIT",false).toBool();
|
||||||
|
m_XIT=settings.value("XIT",0).toInt();
|
||||||
m_plus2kHz=settings.value("Plus2kHz",false).toBool();
|
m_plus2kHz=settings.value("Plus2kHz",false).toBool();
|
||||||
ui->cbPlus2kHz->setChecked(m_plus2kHz);
|
ui->cbPlus2kHz->setChecked(m_plus2kHz);
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
@ -713,7 +709,6 @@ void MainWindow::dataSink(int k)
|
|||||||
watcher2->setFuture(*future2);
|
watcher2->setFuture(*future2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// m_soundInput.m_dataSinkBusy=false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::showSoundInError(const QString& errorMsg)
|
void MainWindow::showSoundInError(const QString& errorMsg)
|
||||||
@ -833,14 +828,11 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
|
|||||||
m_After73=dlg.m_After73;
|
m_After73=dlg.m_After73;
|
||||||
|
|
||||||
if(dlg.m_restartSoundIn) {
|
if(dlg.m_restartSoundIn) {
|
||||||
m_soundInput.stop();
|
|
||||||
m_soundInput.start(m_paInDevice);
|
m_soundInput.start(m_paInDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dlg.m_restartSoundOut) {
|
if(dlg.m_restartSoundOut) {
|
||||||
soundOutThread.quitExecution=true;
|
m_soundOutput.start(m_paOutDevice,m_modeTx,m_TRperiod,m_nsps,m_txFreq,m_bSplit || m_bXIT ? m_XIT : 0);
|
||||||
soundOutThread.wait(1000);
|
|
||||||
soundOutThread.setOutputDevice(m_paOutDevice);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_catEnabled=dlg.m_catEnabled;
|
m_catEnabled=dlg.m_catEnabled;
|
||||||
@ -910,7 +902,8 @@ void MainWindow::on_autoButton_clicked() //Auto
|
|||||||
if(m_auto) {
|
if(m_auto) {
|
||||||
ui->autoButton->setStyleSheet(m_pbAutoOn_style);
|
ui->autoButton->setStyleSheet(m_pbAutoOn_style);
|
||||||
} else {
|
} else {
|
||||||
btxok=false;
|
m_btxok=false;
|
||||||
|
m_soundOutput.mute();
|
||||||
ui->autoButton->setStyleSheet("");
|
ui->autoButton->setStyleSheet("");
|
||||||
on_monitorButton_clicked();
|
on_monitorButton_clicked();
|
||||||
m_repeatMsg=0;
|
m_repeatMsg=0;
|
||||||
@ -1702,7 +1695,7 @@ void MainWindow::guiUpdate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
float fTR=float((nsec%m_TRperiod))/m_TRperiod;
|
float fTR=float((nsec%m_TRperiod))/m_TRperiod;
|
||||||
if(g_iptt==0 and ((bTxTime and !btxMute and fTR<0.4) or m_tune )) {
|
if(g_iptt==0 and ((bTxTime and !m_btxMute and fTR<0.4) or m_tune )) {
|
||||||
icw[0]=m_ncw;
|
icw[0]=m_ncw;
|
||||||
|
|
||||||
//Raise PTT
|
//Raise PTT
|
||||||
@ -1725,8 +1718,9 @@ void MainWindow::guiUpdate()
|
|||||||
}
|
}
|
||||||
ptt1Timer->start(200); //Sequencer delay
|
ptt1Timer->start(200); //Sequencer delay
|
||||||
}
|
}
|
||||||
if(!bTxTime || btxMute) {
|
if(!bTxTime || m_btxMute) {
|
||||||
btxok=false;
|
m_btxok=false;
|
||||||
|
m_soundOutput.mute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1824,7 +1818,8 @@ void MainWindow::guiUpdate()
|
|||||||
signalMeter->setValue(0);
|
signalMeter->setValue(0);
|
||||||
m_monitoring=false;
|
m_monitoring=false;
|
||||||
m_soundInput.setMonitoring(false);
|
m_soundInput.setMonitoring(false);
|
||||||
btxok=true;
|
m_btxok=true;
|
||||||
|
m_soundOutput.mute(false);
|
||||||
m_transmitting=true;
|
m_transmitting=true;
|
||||||
ui->pbTxMode->setEnabled(false);
|
ui->pbTxMode->setEnabled(false);
|
||||||
if(!m_tune) {
|
if(!m_tune) {
|
||||||
@ -1839,11 +1834,11 @@ void MainWindow::guiUpdate()
|
|||||||
if(m_tx2QSO and !m_tune) displayTxMsg(t);
|
if(m_tx2QSO and !m_tune) displayTxMsg(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!btxok && btxok0 && g_iptt==1) stopTx();
|
if(!m_btxok && btxok0 && g_iptt==1) stopTx();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// If btxok was just lowered, start a countdown for lowering PTT
|
// If m_btxok was just lowered, start a countdown for lowering PTT
|
||||||
if(!btxok && btxok0 && g_iptt==1) nc0=-11; //RxDelay = 1.0 s
|
if(!m_btxok && btxok0 && g_iptt==1) nc0=-11; //RxDelay = 1.0 s
|
||||||
if(nc0 <= 0) {
|
if(nc0 <= 0) {
|
||||||
nc0++;
|
nc0++;
|
||||||
}
|
}
|
||||||
@ -1917,7 +1912,7 @@ void MainWindow::guiUpdate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
iptt0=g_iptt;
|
iptt0=g_iptt;
|
||||||
btxok0=btxok;
|
btxok0=m_btxok;
|
||||||
} //End of GUIupdate
|
} //End of GUIupdate
|
||||||
|
|
||||||
void MainWindow::displayTxMsg(QString t)
|
void MainWindow::displayTxMsg(QString t)
|
||||||
@ -1943,17 +1938,16 @@ void MainWindow::displayTxMsg(QString t)
|
|||||||
|
|
||||||
void MainWindow::startTx2()
|
void MainWindow::startTx2()
|
||||||
{
|
{
|
||||||
if(!soundOutThread.isRunning()) {
|
if(!m_soundOutput.isRunning()) {
|
||||||
QString t=ui->tx6->text();
|
QString t=ui->tx6->text();
|
||||||
double snr=t.mid(1,5).toDouble();
|
double snr=t.mid(1,5).toDouble();
|
||||||
if(snr>0.0 or snr < -50.0) snr=99.0;
|
if(snr>0.0 or snr < -50.0) snr=99.0;
|
||||||
soundOutThread.setTxSNR(snr);
|
m_soundOutput.start(m_paOutDevice,m_modeTx,m_TRperiod,m_nsps,m_txFreq,m_bSplit || m_bXIT ? m_XIT : 0,snr);
|
||||||
soundOutThread.m_modeTx=m_modeTx;
|
|
||||||
soundOutThread.start(QThread::HighestPriority);
|
|
||||||
signalMeter->setValue(0);
|
signalMeter->setValue(0);
|
||||||
m_monitoring=false;
|
m_monitoring=false;
|
||||||
m_soundInput.setMonitoring(false);
|
m_soundInput.setMonitoring(false);
|
||||||
btxok=true;
|
m_btxok=true;
|
||||||
|
m_soundOutput.mute(false);
|
||||||
m_transmitting=true;
|
m_transmitting=true;
|
||||||
ui->pbTxMode->setEnabled(false);
|
ui->pbTxMode->setEnabled(false);
|
||||||
}
|
}
|
||||||
@ -1961,10 +1955,7 @@ void MainWindow::startTx2()
|
|||||||
|
|
||||||
void MainWindow::stopTx()
|
void MainWindow::stopTx()
|
||||||
{
|
{
|
||||||
if (soundOutThread.isRunning()) {
|
m_soundOutput.stop();
|
||||||
soundOutThread.quitExecution=true;
|
|
||||||
soundOutThread.wait(3000);
|
|
||||||
}
|
|
||||||
m_transmitting=false;
|
m_transmitting=false;
|
||||||
ui->pbTxMode->setEnabled(true);
|
ui->pbTxMode->setEnabled(true);
|
||||||
g_iptt=0;
|
g_iptt=0;
|
||||||
@ -2482,9 +2473,13 @@ void MainWindow::on_tx6_editingFinished() //tx6 edited
|
|||||||
{
|
{
|
||||||
QString t=ui->tx6->text();
|
QString t=ui->tx6->text();
|
||||||
msgtype(t, ui->tx6);
|
msgtype(t, ui->tx6);
|
||||||
double snr=t.mid(1,5).toDouble();
|
|
||||||
if(snr>0.0 or snr < -50.0) snr=99.0;
|
// G4WJS: disabled setting of snr from msg 6 on live edit, will
|
||||||
soundOutThread.setTxSNR(snr);
|
// still generate noise on next full tx period
|
||||||
|
|
||||||
|
// double snr=t.mid(1,5).toDouble();
|
||||||
|
// if(snr>0.0 or snr < -50.0) snr=99.0;
|
||||||
|
// m_soundOutput.setTxSNR(snr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_dxCallEntry_textChanged(const QString &t) //dxCall changed
|
void MainWindow::on_dxCallEntry_textChanged(const QString &t) //dxCall changed
|
||||||
@ -2581,7 +2576,6 @@ void MainWindow::on_actionJT9_1_triggered()
|
|||||||
m_nsps=6912;
|
m_nsps=6912;
|
||||||
m_hsymStop=173;
|
m_hsymStop=173;
|
||||||
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
||||||
soundOutThread.setPeriod(m_TRperiod,m_nsps);
|
|
||||||
lab3->setStyleSheet("QLabel{background-color: #ff6ec7}");
|
lab3->setStyleSheet("QLabel{background-color: #ff6ec7}");
|
||||||
lab3->setText(m_mode);
|
lab3->setText(m_mode);
|
||||||
ui->actionJT9_1->setChecked(true);
|
ui->actionJT9_1->setChecked(true);
|
||||||
@ -2600,7 +2594,6 @@ void MainWindow::on_actionJT65_triggered()
|
|||||||
m_nsps=6912; //For symspec only
|
m_nsps=6912; //For symspec only
|
||||||
m_hsymStop=173;
|
m_hsymStop=173;
|
||||||
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
||||||
soundOutThread.setPeriod(m_TRperiod,m_nsps);
|
|
||||||
lab3->setStyleSheet("QLabel{background-color: #ffff00}");
|
lab3->setStyleSheet("QLabel{background-color: #ffff00}");
|
||||||
lab3->setText(m_mode);
|
lab3->setText(m_mode);
|
||||||
ui->actionJT65->setChecked(true);
|
ui->actionJT65->setChecked(true);
|
||||||
@ -2619,7 +2612,6 @@ void MainWindow::on_actionJT9_JT65_triggered()
|
|||||||
m_nsps=6912;
|
m_nsps=6912;
|
||||||
m_hsymStop=173;
|
m_hsymStop=173;
|
||||||
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
m_soundInput.setPeriod(m_TRperiod,m_nsps);
|
||||||
soundOutThread.setPeriod(m_TRperiod,m_nsps);
|
|
||||||
lab3->setStyleSheet("QLabel{background-color: #ffa500}");
|
lab3->setStyleSheet("QLabel{background-color: #ffa500}");
|
||||||
lab3->setText(m_mode);
|
lab3->setText(m_mode);
|
||||||
ui->actionJT9_JT65->setChecked(true);
|
ui->actionJT9_JT65->setChecked(true);
|
||||||
@ -2634,7 +2626,7 @@ void MainWindow::on_TxFreqSpinBox_valueChanged(int n)
|
|||||||
m_txFreq=n;
|
m_txFreq=n;
|
||||||
if(g_pWideGraph!=NULL) g_pWideGraph->setTxFreq(n);
|
if(g_pWideGraph!=NULL) g_pWideGraph->setTxFreq(n);
|
||||||
if(m_lockTxFreq) ui->RxFreqSpinBox->setValue(n);
|
if(m_lockTxFreq) ui->RxFreqSpinBox->setValue(n);
|
||||||
soundOutThread.setTxFreq(n);
|
m_soundOutput.setTxFreq(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_RxFreqSpinBox_valueChanged(int n)
|
void MainWindow::on_RxFreqSpinBox_valueChanged(int n)
|
||||||
@ -2964,7 +2956,7 @@ void MainWindow::on_tuneButton_clicked()
|
|||||||
} else {
|
} else {
|
||||||
m_tune=true;
|
m_tune=true;
|
||||||
m_sent73=false;
|
m_sent73=false;
|
||||||
soundOutThread.setTune(m_tune);
|
m_soundOutput.tune(m_tune);
|
||||||
m_repeatMsg=0;
|
m_repeatMsg=0;
|
||||||
ui->tuneButton->setStyleSheet(m_pbTune_style);
|
ui->tuneButton->setStyleSheet(m_pbTune_style);
|
||||||
}
|
}
|
||||||
@ -2974,10 +2966,11 @@ void MainWindow::on_stopTxButton_clicked() //Stop Tx
|
|||||||
{
|
{
|
||||||
if(m_tune) {
|
if(m_tune) {
|
||||||
m_tune=false;
|
m_tune=false;
|
||||||
soundOutThread.setTune(m_tune);
|
m_soundOutput.tune(m_tune);
|
||||||
}
|
}
|
||||||
if(m_auto) on_autoButton_clicked();
|
if(m_auto) on_autoButton_clicked();
|
||||||
btxok=false;
|
m_btxok=false;
|
||||||
|
m_soundOutput.mute();
|
||||||
m_repeatMsg=0;
|
m_repeatMsg=0;
|
||||||
ui->tuneButton->setStyleSheet("");
|
ui->tuneButton->setStyleSheet("");
|
||||||
}
|
}
|
||||||
@ -3094,15 +3087,15 @@ void MainWindow::on_pbTxMode_clicked()
|
|||||||
void MainWindow::setXIT(int n)
|
void MainWindow::setXIT(int n)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int xit=0;
|
m_XIT = 0;
|
||||||
if(m_bRigOpen) {
|
if(m_bRigOpen) {
|
||||||
xit=-1000;
|
m_XIT=-1000;
|
||||||
if(n>1000) xit=0;
|
if(n>1000) m_XIT=0;
|
||||||
if(n>2000) xit=1000;
|
if(n>2000) m_XIT=1000;
|
||||||
if(n>3000) xit=2000;
|
if(n>3000) m_XIT=2000;
|
||||||
if(n>4000) xit=3000;
|
if(n>4000) m_XIT=3000;
|
||||||
if(m_bXIT) {
|
if(m_bXIT) {
|
||||||
ret=rig->setXit((shortfreq_t)xit,RIG_VFO_TX);
|
ret=rig->setXit((shortfreq_t)m_XIT,RIG_VFO_TX);
|
||||||
if(ret!=RIG_OK) {
|
if(ret!=RIG_OK) {
|
||||||
QString rt;
|
QString rt;
|
||||||
rt.sprintf("Setting RIG_VFO_TX failed: %d",ret);
|
rt.sprintf("Setting RIG_VFO_TX failed: %d",ret);
|
||||||
@ -3110,11 +3103,11 @@ void MainWindow::setXIT(int n)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m_bSplit) {
|
if(m_bSplit) {
|
||||||
ret=rig->setSplitFreq(MHz(m_dialFreq)+xit,RIG_VFO_B);
|
ret=rig->setSplitFreq(MHz(m_dialFreq)+m_XIT,RIG_VFO_B);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m_bSplit) soundOutThread.setXIT(xit);
|
if(m_bSplit) m_soundOutput.setXIT(m_XIT);
|
||||||
if(!m_bSplit) soundOutThread.setXIT(0);
|
if(!m_bSplit) m_soundOutput.setXIT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setFreq4(int rxFreq, int txFreq)
|
void MainWindow::setFreq4(int rxFreq, int txFreq)
|
||||||
|
@ -183,6 +183,7 @@ private:
|
|||||||
qint32 m_timeout;
|
qint32 m_timeout;
|
||||||
qint32 m_rxFreq;
|
qint32 m_rxFreq;
|
||||||
qint32 m_txFreq;
|
qint32 m_txFreq;
|
||||||
|
int m_XIT;
|
||||||
qint32 m_setftx;
|
qint32 m_setftx;
|
||||||
qint32 m_ndepth;
|
qint32 m_ndepth;
|
||||||
qint32 m_sec0;
|
qint32 m_sec0;
|
||||||
@ -219,6 +220,8 @@ private:
|
|||||||
qint32 m_bad;
|
qint32 m_bad;
|
||||||
|
|
||||||
bool m_monitoring;
|
bool m_monitoring;
|
||||||
|
bool m_btxok; //True if OK to transmit
|
||||||
|
bool m_btxMute; //True if transmit should be muted
|
||||||
bool m_transmitting;
|
bool m_transmitting;
|
||||||
bool m_diskData;
|
bool m_diskData;
|
||||||
bool m_loopall;
|
bool m_loopall;
|
||||||
@ -341,7 +344,7 @@ private:
|
|||||||
QDateTime m_dateTimeQSO;
|
QDateTime m_dateTimeQSO;
|
||||||
|
|
||||||
SoundInput m_soundInput; //Instantiate the audio objects
|
SoundInput m_soundInput; //Instantiate the audio objects
|
||||||
SoundOutThread soundOutThread;
|
SoundOutput m_soundOutput;
|
||||||
QSharedMemory *mem_jt9;
|
QSharedMemory *mem_jt9;
|
||||||
// Multiple instances:
|
// Multiple instances:
|
||||||
QString *mykey_jt9;
|
QString *mykey_jt9;
|
||||||
|
67
soundin.cpp
67
soundin.cpp
@ -1,6 +1,8 @@
|
|||||||
#ifndef QAUDIO_INPUT
|
#ifndef QAUDIO_INPUT
|
||||||
#include "soundin.h"
|
#include "soundin.h"
|
||||||
#include <stdexcept>
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#define FRAMES_PER_BUFFER 1024
|
#define FRAMES_PER_BUFFER 1024
|
||||||
#define NSMAX 6827
|
#define NSMAX 6827
|
||||||
@ -48,29 +50,28 @@ int a2dCallback( const void *inputBuffer, void * /* outputBuffer */,
|
|||||||
SoundInput::CallbackData * udata = reinterpret_cast<SoundInput::CallbackData *>(userData);
|
SoundInput::CallbackData * udata = reinterpret_cast<SoundInput::CallbackData *>(userData);
|
||||||
int nbytes,k;
|
int nbytes,k;
|
||||||
|
|
||||||
udata->ncall++;
|
|
||||||
if( (statusFlags&paInputOverflow) != 0) {
|
if( (statusFlags&paInputOverflow) != 0) {
|
||||||
qDebug() << "Input Overflow in a2dCallback";
|
qDebug() << "Input Overflow in a2dCallback";
|
||||||
}
|
}
|
||||||
if(udata->bzero) { //Start of a new Rx sequence
|
if(udata->bzero)
|
||||||
udata->kin=0; //Reset buffer pointer
|
{ //Start of a new Rx sequence
|
||||||
udata->bzero=false;
|
udata->kin = 0; //Reset buffer pointer
|
||||||
}
|
udata->bzero = false;
|
||||||
|
}
|
||||||
|
|
||||||
nbytes=2*framesToProcess; //Bytes per frame
|
nbytes=2*framesToProcess; //Bytes per frame
|
||||||
k=udata->kin;
|
k=udata->kin;
|
||||||
if(udata->monitoring) {
|
if(udata->monitoring) {
|
||||||
memcpy(&jt9com_.d2[k],inputBuffer,nbytes); //Copy all samples to d2
|
memcpy(&jt9com_.d2[k],inputBuffer,nbytes); //Copy all samples to d2
|
||||||
}
|
}
|
||||||
udata->kin += framesToProcess;
|
udata->kin+=framesToProcess;
|
||||||
jt9com_.kin=udata->kin;
|
jt9com_.kin=udata->kin; // we are the only writer to jt9com_ so no MT issue here
|
||||||
|
|
||||||
return paContinue;
|
return paContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundInput::SoundInput()
|
SoundInput::SoundInput()
|
||||||
: m_inStream(0),
|
: m_inStream(0),
|
||||||
m_dataSinkBusy(false),
|
|
||||||
m_TRperiod(60),
|
m_TRperiod(60),
|
||||||
m_nsps(6912),
|
m_nsps(6912),
|
||||||
m_monitoring(false),
|
m_monitoring(false),
|
||||||
@ -87,10 +88,9 @@ void SoundInput::start(qint32 device)
|
|||||||
PaError paerr;
|
PaError paerr;
|
||||||
PaStreamParameters inParam;
|
PaStreamParameters inParam;
|
||||||
|
|
||||||
m_callbackData.kin=0; //Buffer pointer
|
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.bzero=false; //Flag to request reset of kin
|
m_callbackData.monitoring = m_monitoring;
|
||||||
m_callbackData.monitoring=m_monitoring;
|
|
||||||
|
|
||||||
inParam.device=device; //### Input Device Number ###
|
inParam.device=device; //### Input Device Number ###
|
||||||
inParam.channelCount=1; //Number of analog channels
|
inParam.channelCount=1; //Number of analog channels
|
||||||
@ -101,9 +101,7 @@ void SoundInput::start(qint32 device)
|
|||||||
paerr=Pa_IsFormatSupported(&inParam,NULL,12000.0);
|
paerr=Pa_IsFormatSupported(&inParam,NULL,12000.0);
|
||||||
if(paerr<0) {
|
if(paerr<0) {
|
||||||
emit error("PortAudio says requested soundcard format not supported.");
|
emit error("PortAudio says requested soundcard format not supported.");
|
||||||
// return;
|
|
||||||
}
|
}
|
||||||
qDebug() << "";
|
|
||||||
paerr=Pa_OpenStream(&m_inStream, //Input stream
|
paerr=Pa_OpenStream(&m_inStream, //Input stream
|
||||||
&inParam, //Input parameters
|
&inParam, //Input parameters
|
||||||
NULL, //No output parameters
|
NULL, //No output parameters
|
||||||
@ -119,7 +117,6 @@ void SoundInput::start(qint32 device)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_ntr0 = 99; // initial value higher than any expected
|
m_ntr0 = 99; // initial value higher than any expected
|
||||||
m_nBusy = 0;
|
|
||||||
m_intervalTimer.start(100);
|
m_intervalTimer.start(100);
|
||||||
m_ms0 = QDateTime::currentMSecsSinceEpoch();
|
m_ms0 = QDateTime::currentMSecsSinceEpoch();
|
||||||
m_nsps0 = 0;
|
m_nsps0 = 0;
|
||||||
@ -127,35 +124,32 @@ void SoundInput::start(qint32 device)
|
|||||||
|
|
||||||
void SoundInput::intervalNotify()
|
void SoundInput::intervalNotify()
|
||||||
{
|
{
|
||||||
m_callbackData.monitoring=m_monitoring;
|
m_callbackData.monitoring = m_monitoring; // update monitoring
|
||||||
|
// status
|
||||||
|
|
||||||
qint64 ms = QDateTime::currentMSecsSinceEpoch();
|
qint64 ms = QDateTime::currentMSecsSinceEpoch();
|
||||||
m_SamFacIn=1.0;
|
|
||||||
if(m_callbackData.ncall>100) {
|
|
||||||
m_SamFacIn=m_callbackData.ncall*FRAMES_PER_BUFFER*1000.0/(12000.0*(ms-m_ms0-50));
|
|
||||||
}
|
|
||||||
ms=ms % 86400000;
|
ms=ms % 86400000;
|
||||||
int nsec = ms/1000; // Time according to this computer
|
int nsec = ms/1000; // Time according to this computer
|
||||||
int ntr = nsec % m_TRperiod;
|
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
|
// Reset buffer pointer and symbol number at start of minute
|
||||||
if(ntr < m_ntr0 or !m_monitoring or m_nsps!=m_nsps0) {
|
if(ntr < m_ntr0 or !m_monitoring or m_nsps!=m_nsps0) {
|
||||||
m_nstep0=0;
|
m_nstep0=0;
|
||||||
m_nsps0=m_nsps;
|
m_nsps0=m_nsps;
|
||||||
m_callbackData.bzero=true;
|
m_callbackData.bzero = true; // request callback to reset buffer pointer
|
||||||
}
|
}
|
||||||
int k=m_callbackData.kin;
|
|
||||||
if(m_monitoring) {
|
if(m_monitoring) {
|
||||||
int kstep=m_nsps/2;
|
int kstep=m_nsps/2;
|
||||||
// m_step=k/kstep;
|
// m_step=k/kstep;
|
||||||
m_step=(k-1)/kstep;
|
m_step=(k-1)/kstep;
|
||||||
if(m_step != m_nstep0) {
|
if(m_step != m_nstep0) {
|
||||||
if(m_dataSinkBusy) {
|
emit readyForFFT(k-1); //Signal to compute new FFTs
|
||||||
m_nBusy++;
|
|
||||||
} else {
|
|
||||||
// m_dataSinkBusy=true;
|
|
||||||
// emit readyForFFT(k); //Signal to compute new FFTs
|
|
||||||
emit readyForFFT(k-1); //Signal to compute new FFTs
|
|
||||||
}
|
|
||||||
m_nstep0=m_step;
|
m_nstep0=m_step;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,14 +174,11 @@ void SoundInput::stop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundInput::setMonitoring(bool b)
|
|
||||||
{
|
|
||||||
m_monitoring = b;
|
|
||||||
}
|
|
||||||
#else // QAUDIO_INPUT
|
#else // QAUDIO_INPUT
|
||||||
|
|
||||||
#include "soundin.h"
|
#include "soundin.h"
|
||||||
#include <stdexcept>
|
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
#define FRAMES_PER_BUFFER 1024
|
#define FRAMES_PER_BUFFER 1024
|
||||||
#define NSMAX 6827
|
#define NSMAX 6827
|
||||||
@ -381,8 +372,4 @@ void SoundInput::stop()
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundInput::setMonitoring(bool b)
|
|
||||||
{
|
|
||||||
m_monitoring = b;
|
|
||||||
}
|
|
||||||
#endif // QAUDIO_INPUT
|
#endif // QAUDIO_INPUT
|
||||||
|
42
soundin.h
42
soundin.h
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
#include <portaudio.h>
|
#include <portaudio.h>
|
||||||
|
|
||||||
#include <QtCore>
|
#include <QObject>
|
||||||
#include <QScopedPointer>
|
#include <QTimer>
|
||||||
#include <QDebug>
|
#include <QString>
|
||||||
|
|
||||||
extern "C" int a2dCallback( const void *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
|
extern "C" int a2dCallback( const void *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
|
||||||
|
|
||||||
@ -20,14 +20,15 @@ public:
|
|||||||
SoundInput();
|
SoundInput();
|
||||||
~SoundInput();
|
~SoundInput();
|
||||||
|
|
||||||
void setMonitoring(bool b);
|
int mstep() const {return m_step;}
|
||||||
void setPeriod(int ntrperiod, int nsps) /* this can be called while processing samples */
|
|
||||||
|
/* these can be called while processing samples */
|
||||||
|
void setMonitoring(bool b) {m_monitoring = b;}
|
||||||
|
void setPeriod(int ntrperiod, int nsps)
|
||||||
{
|
{
|
||||||
m_TRperiod=ntrperiod;
|
m_TRperiod=ntrperiod;
|
||||||
m_nsps=nsps;
|
m_nsps=nsps;
|
||||||
}
|
}
|
||||||
int mstep() const {return m_step;}
|
|
||||||
double samFacIn() const {return m_SamFacIn;}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void readyForFFT(int k);
|
void readyForFFT(int k);
|
||||||
@ -36,13 +37,10 @@ signals:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start(qint32 device);
|
void start(qint32 device);
|
||||||
void intervalNotify();
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PaStream * m_inStream;
|
PaStream * m_inStream;
|
||||||
bool m_dataSinkBusy;
|
|
||||||
double m_SamFacIn; //(Input sample rate)/12000.0
|
|
||||||
qint32 m_step;
|
qint32 m_step;
|
||||||
qint32 m_TRperiod;
|
qint32 m_TRperiod;
|
||||||
qint32 m_TRperiod0;
|
qint32 m_TRperiod0;
|
||||||
@ -50,7 +48,6 @@ private:
|
|||||||
bool m_monitoring;
|
bool m_monitoring;
|
||||||
qint64 m_ms0;
|
qint64 m_ms0;
|
||||||
int m_ntr0;
|
int m_ntr0;
|
||||||
int m_nBusy;
|
|
||||||
int m_nstep0;
|
int m_nstep0;
|
||||||
int m_nsps0;
|
int m_nsps0;
|
||||||
|
|
||||||
@ -58,23 +55,26 @@ private:
|
|||||||
|
|
||||||
struct CallbackData
|
struct CallbackData
|
||||||
{
|
{
|
||||||
int kin; //Parameters sent to/from the portaudio callback function
|
//Parameters sent to/from the portaudio callback function
|
||||||
int ncall;
|
int volatile kin;
|
||||||
bool bzero;
|
bool volatile bzero;
|
||||||
bool monitoring;
|
bool volatile monitoring;
|
||||||
} m_callbackData;
|
} m_callbackData;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void intervalNotify();
|
||||||
|
|
||||||
friend int a2dCallback(void const *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
|
friend int a2dCallback(void const *, void *, unsigned long, PaStreamCallbackTimeInfo const *, PaStreamCallbackFlags, void *);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SOUNDIN_H
|
#endif // SOUNDIN_H
|
||||||
|
|
||||||
#else // QAUDIO_INPUT
|
#else // QAUDIO_INPUT
|
||||||
#ifndef SOUNDIN_H
|
#ifndef SOUNDIN_H
|
||||||
#define SOUNDIN_H
|
#define SOUNDIN_H
|
||||||
|
|
||||||
#include <QtCore>
|
#include <QObject>
|
||||||
#include <QScopedPointer>
|
#include <QTimer>
|
||||||
#include <QDebug>
|
|
||||||
#include <QAudioDeviceInfo>
|
#include <QAudioDeviceInfo>
|
||||||
#include <QAudioInput>
|
#include <QAudioInput>
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ public:
|
|||||||
SoundInput();
|
SoundInput();
|
||||||
~SoundInput();
|
~SoundInput();
|
||||||
|
|
||||||
void setMonitoring(bool b);
|
void setMonitoring(bool b) {m_monitoring = b;}
|
||||||
void setPeriod(int ntrperiod, int nsps) /* this can be called while processing samples */
|
void setPeriod(int ntrperiod, int nsps) /* this can be called while processing samples */
|
||||||
{
|
{
|
||||||
m_TRperiod=ntrperiod;
|
m_TRperiod=ntrperiod;
|
||||||
@ -104,7 +104,6 @@ signals:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start(qint32 device);
|
void start(qint32 device);
|
||||||
void intervalNotify();
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -133,6 +132,9 @@ private:
|
|||||||
bool bzero;
|
bool bzero;
|
||||||
bool monitoring;
|
bool monitoring;
|
||||||
} m_callbackData; //Parameters sent to/from the Notify function
|
} m_callbackData; //Parameters sent to/from the Notify function
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void intervalNotify();
|
||||||
};
|
};
|
||||||
#endif // SOUNDIN_H
|
#endif // SOUNDIN_H
|
||||||
#endif // QAUDIO_INPUT
|
#endif // QAUDIO_INPUT
|
||||||
|
193
soundout.cpp
193
soundout.cpp
@ -1,42 +1,28 @@
|
|||||||
#include "soundout.h"
|
#include "soundout.h"
|
||||||
|
|
||||||
//#define FRAMES_PER_BUFFER 1024
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
extern "C" {
|
#include <QDateTime>
|
||||||
#include <portaudio.h>
|
#include <QDebug>
|
||||||
}
|
|
||||||
|
//#define FRAMES_PER_BUFFER 1024
|
||||||
|
|
||||||
extern float gran(); //Noise generator (for tests only)
|
extern float gran(); //Noise generator (for tests only)
|
||||||
extern int itone[126]; //Audio tones for all Tx symbols
|
extern int itone[126]; //Audio tones for all Tx symbols
|
||||||
extern int icw[250]; //Dits for CW ID
|
extern int icw[250]; //Dits for CW ID
|
||||||
extern int outBufSize;
|
extern int outBufSize;
|
||||||
extern bool btxok;
|
|
||||||
extern bool btxMute;
|
|
||||||
extern double outputLatency;
|
|
||||||
|
|
||||||
typedef struct //Parameters sent to or received from callback function
|
|
||||||
{
|
|
||||||
double txsnrdb;
|
|
||||||
double dnsps;
|
|
||||||
int ntrperiod;
|
|
||||||
int ntxfreq;
|
|
||||||
int xit;
|
|
||||||
int ncall;
|
|
||||||
int nsym;
|
|
||||||
bool txMute;
|
|
||||||
bool bRestart;
|
|
||||||
bool btune;
|
|
||||||
} paUserData;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------- d2aCallback
|
//--------------------------------------------------------------- d2aCallback
|
||||||
extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
||||||
unsigned long framesToProcess,
|
unsigned long framesToProcess,
|
||||||
const PaStreamCallbackTimeInfo* timeInfo,
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
PaStreamCallbackFlags statusFlags,
|
PaStreamCallbackFlags statusFlags,
|
||||||
void *userData )
|
void *userData )
|
||||||
{
|
{
|
||||||
paUserData *udata=(paUserData*)userData;
|
SoundOutput::CallbackData * udata = reinterpret_cast<SoundOutput::CallbackData *>(userData);
|
||||||
short *wptr = (short*)outputBuffer;
|
short * wptr = reinterpret_cast<short *>(outputBuffer);
|
||||||
|
|
||||||
static double twopi=2.0*3.141592653589793238462;
|
static double twopi=2.0*3.141592653589793238462;
|
||||||
static double baud;
|
static double baud;
|
||||||
@ -56,15 +42,19 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
// Time according to this computer
|
// Time according to this computer
|
||||||
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||||
int mstr = ms % (1000*udata->ntrperiod );
|
int mstr = ms % (1000*udata->ntrperiod );
|
||||||
if(mstr<1000) return paContinue;
|
if(mstr<1000)
|
||||||
|
{
|
||||||
|
std::memset(wptr, 0, framesToProcess * sizeof(*wptr)); // output silence
|
||||||
|
return paContinue;
|
||||||
|
}
|
||||||
ic=(mstr-1000)*48;
|
ic=(mstr-1000)*48;
|
||||||
udata->bRestart=false;
|
udata->bRestart=false;
|
||||||
srand(mstr); //Initialize random seed
|
srand(mstr); //Initialize random seed
|
||||||
}
|
}
|
||||||
isym=ic/(4.0*udata->dnsps); //Actual fsample=48000
|
isym=ic/(4.0*udata->dnsps); //Actual fsample=48000
|
||||||
if(udata->btune) isym=0; //If tuning, send pure tone
|
if(udata->tune) isym=0; //If tuning, send pure tone
|
||||||
if(udata->txsnrdb < 0.0) {
|
if(udata->txsnrdb < 0.0) {
|
||||||
snr=pow(10.0,0.05*(udata->txsnrdb-6.0));
|
snr=std::pow(10.0,0.05*(udata->txsnrdb-6.0));
|
||||||
fac=3000.0;
|
fac=3000.0;
|
||||||
if(snr>1.0) fac=3000.0/snr;
|
if(snr>1.0) fac=3000.0/snr;
|
||||||
}
|
}
|
||||||
@ -81,7 +71,7 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
for(uint i=0 ; i<framesToProcess; i++ ) {
|
for(uint i=0 ; i<framesToProcess; i++ ) {
|
||||||
phi += dphi;
|
phi += dphi;
|
||||||
if(phi>twopi) phi -= twopi;
|
if(phi>twopi) phi -= twopi;
|
||||||
i2=32767.0*sin(phi);
|
i2=32767.0*std::sin(phi);
|
||||||
j=(ic-ic0)/nspd + 1;
|
j=(ic-ic0)/nspd + 1;
|
||||||
if(icw[j]==0) i2=0;
|
if(icw[j]==0) i2=0;
|
||||||
if(udata->txsnrdb < 0.0) {
|
if(udata->txsnrdb < 0.0) {
|
||||||
@ -90,7 +80,7 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
if(i4<-32767) i4=-32767;
|
if(i4<-32767) i4=-32767;
|
||||||
i2=i4;
|
i2=i4;
|
||||||
}
|
}
|
||||||
if(!btxok or btxMute) i2=0;
|
if(udata->mute) i2=0;
|
||||||
*wptr++ = i2; //left
|
*wptr++ = i2; //left
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
*wptr++ = i2; //right
|
*wptr++ = i2; //right
|
||||||
@ -107,13 +97,14 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
amp=32767.0;
|
amp=32767.0;
|
||||||
int i0=(udata->nsym-0.017)*4.0*udata->dnsps;
|
int i0=(udata->nsym-0.017)*4.0*udata->dnsps;
|
||||||
int i1=udata->nsym*4.0*udata->dnsps;
|
int i1=udata->nsym*4.0*udata->dnsps;
|
||||||
if(udata->btune) { //If tuning, no ramp down
|
bool tune = udata->tune;
|
||||||
|
if(tune) { //If tuning, no ramp down
|
||||||
i0=999*udata->dnsps;
|
i0=999*udata->dnsps;
|
||||||
i1=i0;
|
i1=i0;
|
||||||
}
|
}
|
||||||
for(uint i=0 ; i<framesToProcess; i++ ) {
|
for(uint i=0 ; i<framesToProcess; i++ ) {
|
||||||
isym=ic/(4.0*udata->dnsps); //Actual fsample=48000
|
isym=ic/(4.0*udata->dnsps); //Actual fsample=48000
|
||||||
if(udata->btune) isym=0; //If tuning, send pure tone
|
if(tune) isym=0; //If tuning, send pure tone
|
||||||
if(isym!=isym0) {
|
if(isym!=isym0) {
|
||||||
freq=udata->ntxfreq + itone[isym]*baud - udata->xit;
|
freq=udata->ntxfreq + itone[isym]*baud - udata->xit;
|
||||||
dphi=twopi*freq/48000.0;
|
dphi=twopi*freq/48000.0;
|
||||||
@ -123,14 +114,14 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
if(phi>twopi) phi -= twopi;
|
if(phi>twopi) phi -= twopi;
|
||||||
if(ic>i0) amp=0.98*amp;
|
if(ic>i0) amp=0.98*amp;
|
||||||
if(ic>i1) amp=0.0;
|
if(ic>i1) amp=0.0;
|
||||||
i2=amp*sin(phi);
|
i2=amp*std::sin(phi);
|
||||||
if(udata->txsnrdb < 0.0) {
|
if(udata->txsnrdb < 0.0) {
|
||||||
int i4=fac*(gran() + i2*snr/32768.0);
|
int i4=fac*(gran() + i2*snr/32768.0);
|
||||||
if(i4>32767) i4=32767;
|
if(i4>32767) i4=32767;
|
||||||
if(i4<-32767) i4=-32767;
|
if(i4<-32767) i4=-32767;
|
||||||
i2=i4;
|
i2=i4;
|
||||||
}
|
}
|
||||||
if(!btxok or btxMute) i2=0;
|
if(udata->mute) i2=0;
|
||||||
*wptr++ = i2; //left
|
*wptr++ = i2; //left
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
*wptr++ = i2; //right
|
*wptr++ = i2; //right
|
||||||
@ -144,15 +135,21 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
return paContinue;
|
return paContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundOutThread::run()
|
SoundOutput::SoundOutput()
|
||||||
|
: m_stream(0)
|
||||||
|
, m_outputLatency(0.)
|
||||||
|
, m_active(false)
|
||||||
{
|
{
|
||||||
PaError paerr;
|
}
|
||||||
PaStreamParameters outParam;
|
|
||||||
PaStream *outStream;
|
|
||||||
paUserData udata;
|
|
||||||
quitExecution = false;
|
|
||||||
|
|
||||||
outParam.device=m_nDevOut; //Output device number
|
void SoundOutput::start(qint32 deviceNumber,QString const& mode,int TRPeriod
|
||||||
|
,int nsps,int txFreq,int xit,double txsnrdb)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
|
||||||
|
PaStreamParameters outParam;
|
||||||
|
|
||||||
|
outParam.device=deviceNumber; //Output device number
|
||||||
outParam.channelCount=1; //Number of analog channels
|
outParam.channelCount=1; //Number of analog channels
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
outParam.channelCount=2; //Number of analog channels
|
outParam.channelCount=2; //Number of analog channels
|
||||||
@ -161,110 +158,60 @@ void SoundOutThread::run()
|
|||||||
outParam.suggestedLatency=0.05;
|
outParam.suggestedLatency=0.05;
|
||||||
outParam.hostApiSpecificStreamInfo=NULL;
|
outParam.hostApiSpecificStreamInfo=NULL;
|
||||||
|
|
||||||
paerr=Pa_IsFormatSupported(NULL,&outParam,48000.0);
|
PaError paerr = Pa_IsFormatSupported(NULL,&outParam,48000.0);
|
||||||
if(paerr<0) {
|
if(paerr<0) {
|
||||||
qDebug() << "PortAudio says requested output format not supported.";
|
qDebug() << "PortAudio says requested output format not supported.";
|
||||||
qDebug() << paerr << m_nDevOut;
|
qDebug() << paerr << deviceNumber;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
udata.txsnrdb=99.0;
|
m_callbackData.txsnrdb=txsnrdb;
|
||||||
udata.dnsps=m_nsps;
|
m_callbackData.dnsps=nsps;
|
||||||
udata.nsym=85;
|
m_callbackData.nsym=85;
|
||||||
if(m_modeTx=="JT65") {
|
if(mode=="JT65") {
|
||||||
udata.dnsps=4096.0*12000.0/11025.0;
|
m_callbackData.dnsps=4096.0*12000.0/11025.0;
|
||||||
udata.nsym=126;
|
m_callbackData.nsym=126;
|
||||||
}
|
}
|
||||||
udata.ntrperiod=m_TRperiod;
|
m_callbackData.ntrperiod=TRPeriod;
|
||||||
udata.ntxfreq=m_txFreq;
|
m_callbackData.ntxfreq=txFreq;
|
||||||
udata.xit=m_xit;
|
m_callbackData.xit=xit;
|
||||||
udata.ncall=0;
|
m_callbackData.ncall=0;
|
||||||
udata.txMute=m_txMute;
|
m_callbackData.bRestart=true;
|
||||||
udata.bRestart=true;
|
|
||||||
udata.btune=m_tune;
|
|
||||||
|
|
||||||
paerr=Pa_OpenStream(&outStream, //Output stream
|
paerr=Pa_OpenStream(&m_stream, //Output stream
|
||||||
NULL, //No input parameters
|
NULL, //No input parameters
|
||||||
&outParam, //Output parameters
|
&outParam, //Output parameters
|
||||||
48000.0, //Sample rate
|
48000.0, //Sample rate
|
||||||
outBufSize, //Frames per buffer
|
outBufSize, //Frames per buffer
|
||||||
paClipOff, //No clipping
|
paClipOff, //No clipping
|
||||||
d2aCallback, //output callbeck routine
|
d2aCallback, //output callbeck routine
|
||||||
&udata); //userdata
|
&m_callbackData); //userdata
|
||||||
|
|
||||||
paerr=Pa_StartStream(outStream);
|
paerr=Pa_StartStream(m_stream);
|
||||||
if(paerr<0) {
|
if(paerr<0) {
|
||||||
qDebug() << "Failed to start audio output stream.";
|
qDebug() << "Failed to start audio output stream.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const PaStreamInfo* p=Pa_GetStreamInfo(outStream);
|
const PaStreamInfo* p=Pa_GetStreamInfo(m_stream);
|
||||||
outputLatency = p->outputLatency;
|
m_outputLatency = p->outputLatency;
|
||||||
bool qe = quitExecution;
|
m_ms0 = QDateTime::currentMSecsSinceEpoch();
|
||||||
qint64 ms0 = QDateTime::currentMSecsSinceEpoch();
|
m_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------- Soundcard output loop
|
void SoundOutput::stop()
|
||||||
while (!qe) {
|
{
|
||||||
qe = quitExecution;
|
if (m_stream)
|
||||||
if (qe) break;
|
{
|
||||||
|
Pa_StopStream(m_stream);
|
||||||
udata.txsnrdb=m_txsnrdb;
|
Pa_CloseStream(m_stream), m_stream = 0;
|
||||||
udata.dnsps=m_nsps;
|
|
||||||
udata.nsym=85;
|
|
||||||
if(m_modeTx=="JT65") {
|
|
||||||
udata.dnsps=4096.0*12000.0/11025.0;
|
|
||||||
udata.nsym=126;
|
|
||||||
}
|
}
|
||||||
udata.ntrperiod=m_TRperiod;
|
m_active = false;
|
||||||
udata.ntxfreq=m_txFreq;
|
}
|
||||||
udata.xit=m_xit;
|
|
||||||
udata.txMute=m_txMute;
|
|
||||||
udata.btune=m_tune;
|
|
||||||
|
|
||||||
m_SamFacOut=1.0;
|
SoundOutput::~SoundOutput()
|
||||||
if(udata.ncall>400) {
|
{
|
||||||
qint64 ms = QDateTime::currentMSecsSinceEpoch();
|
if (m_stream)
|
||||||
m_SamFacOut=udata.ncall*outBufSize*1000.0/(48000.0*(ms-ms0-50));
|
{
|
||||||
|
Pa_CloseStream(m_stream), m_stream = 0;
|
||||||
}
|
}
|
||||||
msleep(100);
|
|
||||||
}
|
|
||||||
Pa_StopStream(outStream);
|
|
||||||
Pa_CloseStream(outStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundOutThread::setOutputDevice(int n) //setOutputDevice()
|
|
||||||
{
|
|
||||||
if (isRunning()) return;
|
|
||||||
this->m_nDevOut=n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundOutThread::setPeriod(int ntrperiod, int nsps)
|
|
||||||
{
|
|
||||||
m_TRperiod=ntrperiod;
|
|
||||||
m_nsps=nsps;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundOutThread::setTxFreq(int n)
|
|
||||||
{
|
|
||||||
m_txFreq=n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundOutThread::setXIT(int n)
|
|
||||||
{
|
|
||||||
m_xit=n;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundOutThread::setTxSNR(double snr)
|
|
||||||
{
|
|
||||||
m_txsnrdb=snr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundOutThread::setTune(bool b)
|
|
||||||
{
|
|
||||||
m_tune=b;
|
|
||||||
}
|
|
||||||
|
|
||||||
double SoundOutThread::samFacOut()
|
|
||||||
{
|
|
||||||
return m_SamFacOut;
|
|
||||||
}
|
}
|
||||||
|
91
soundout.h
91
soundout.h
@ -1,53 +1,76 @@
|
|||||||
#ifndef SOUNDOUT_H
|
#ifndef SOUNDOUT_H
|
||||||
#define SOUNDOUT_H
|
#define SOUNDOUT_H
|
||||||
#include <QtCore>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
// An instance of this thread sends audio data to a specified soundcard.
|
#include <portaudio.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
extern "C" int d2aCallback(const void *, void *,
|
||||||
|
unsigned long,
|
||||||
|
PaStreamCallbackTimeInfo const *,
|
||||||
|
PaStreamCallbackFlags,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
// An instance of this sends audio data to a specified soundcard.
|
||||||
// Output can be muted while underway, preserving waveform timing when
|
// Output can be muted while underway, preserving waveform timing when
|
||||||
// transmission is resumed.
|
// transmission is resumed.
|
||||||
|
|
||||||
class SoundOutThread : public QThread
|
class SoundOutput : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT;
|
||||||
|
|
||||||
protected:
|
Q_PROPERTY(bool running READ isRunning);
|
||||||
virtual void run();
|
Q_PROPERTY(bool mute READ isMuted WRITE mute);
|
||||||
|
Q_PROPERTY(bool tune READ isTuning WRITE tune);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructs (but does not start) a SoundOutThread
|
SoundOutput();
|
||||||
SoundOutThread()
|
~SoundOutput();
|
||||||
: quitExecution(false) // Initialize some private members
|
|
||||||
, m_txOK(false)
|
|
||||||
, m_txMute(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
bool isRunning() const {return m_active;}
|
||||||
void setOutputDevice(qint32 n);
|
bool isMuted() const {return m_callbackData.mute;}
|
||||||
void setPeriod(int ntrperiod, int nsps);
|
bool isTuning() const {return m_callbackData.tune;}
|
||||||
void setTxFreq(int n);
|
double outputLatency() const {return m_outputLatency;}
|
||||||
void setXIT(int n);
|
|
||||||
void setTxSNR(double snr);
|
// the following can be called while the stream is running
|
||||||
void setTune(bool b);
|
void setTxFreq(int n) {m_callbackData.ntxfreq = n;}
|
||||||
double samFacOut();
|
void setXIT(int n) {m_callbackData.xit = n;}
|
||||||
bool quitExecution; //If true, thread exits gracefully
|
void mute(bool b = true) {m_callbackData.mute = b;}
|
||||||
QString m_modeTx;
|
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.);
|
||||||
|
void stop();
|
||||||
|
|
||||||
// Private members
|
// Private members
|
||||||
private:
|
private:
|
||||||
double m_txsnrdb; //if < 0, add noise to Tx audio
|
PaStream * m_stream;
|
||||||
double m_SamFacOut; //(Output sample rate)/48000.0
|
PaTime m_outputLatency;
|
||||||
|
|
||||||
qint32 m_nDevOut; //Output device number
|
struct CallbackData
|
||||||
qint32 m_TRperiod; //T/R period (s)
|
{
|
||||||
qint32 m_nsps; //Samples per symbol (at 12000 Hz)
|
//Parameters sent to or received from callback function
|
||||||
qint32 m_txFreq;
|
double volatile txsnrdb;
|
||||||
qint32 m_xit;
|
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;
|
||||||
|
|
||||||
bool m_txOK; //Enable Tx audio
|
qint64 m_ms0;
|
||||||
bool m_txMute; //Mute temporarily
|
bool m_active;
|
||||||
bool m_tune;
|
|
||||||
|
friend int d2aCallback(const void *, void *,
|
||||||
|
unsigned long,
|
||||||
|
PaStreamCallbackTimeInfo const *,
|
||||||
|
PaStreamCallbackFlags,
|
||||||
|
void *);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user