mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-12-24 11:40:31 -05:00
Made the soft keying CW wave shaper a CMake option (off by
default). Reorganized Modulator interface so that it can control the stream it writes to. Make sure only QAudioOutput::stop is called at the end of sending rather than QAudioOutput::reset which discards pending samples. Added a quick close option to the Modulator::stop slot to discard pending buffers if required. Fix issue in CW synthesizer that was causing CW to be inverted occasionally. Made global arrays of symbols volatile because compiler waa optimizing away reads in sound thread. These global variables must go eventually as they are a multi-threading hazard. Simplified TX sequencing to remove some duplicate signals. Increased range of TX attenuator from 10dB to 30dB. This is mainly for non-Windows platforms where the attenuator isn't linearized correctly. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3985 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
dbda79e7a2
commit
f076c37c19
@ -24,6 +24,7 @@ option (WSJT_TRACE_CAT "Debugging option that turns on CAT diagnostics.")
|
||||
option (WSJT_TRACE_CAT_POLLS "Debugging option that turns on CAT diagnostics during polling.")
|
||||
option (WSJT_HAMLIB_TRACE "Debugging option that turns on full Hamlib internal diagnostics.")
|
||||
option (WSJT_STANDARD_FILE_LOCATIONS "All non-installation files located in \"Standard\" platfom specific locations." ON)
|
||||
option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients.")
|
||||
|
||||
|
||||
#
|
||||
|
@ -1891,11 +1891,6 @@ void Configuration::impl::handle_transceiver_update (TransceiverState state)
|
||||
Q_EMIT tx_frequency (TransceiverFactory::split_mode_none != split_mode_selected ? state.tx_frequency () : 0, true);
|
||||
}
|
||||
setup_split_ = false;
|
||||
|
||||
// if (TransceiverFactory::split_mode_emulate == split_mode_selected)
|
||||
// {
|
||||
// state.split (true); // complete the illusion
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -89,8 +89,7 @@ void EmulateSplitTransceiver::handle_update (TransceiverState state)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Always emit rigs split state so clients can detect abuse.
|
||||
state.split (true);
|
||||
state.split (true); // override rig state
|
||||
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "EmulateSplitTransceiver::handle_update: signalling:" << state;
|
||||
|
@ -12,9 +12,9 @@ extern float gran(); // Noise generator (for tests only)
|
||||
#define RAMP_INCREMENT 64 // MUST be an integral factor of 2^16
|
||||
|
||||
#if defined (WSJT_SOFT_KEYING)
|
||||
# define SOFT_KEYING true
|
||||
# define SOFT_KEYING WSJT_SOFT_KEYING
|
||||
#else
|
||||
# define SOFT_KEYING false
|
||||
# define SOFT_KEYING 0
|
||||
#endif
|
||||
|
||||
double const Modulator::m_twoPi = 2.0 * 3.141592653589793238462;
|
||||
@ -27,6 +27,7 @@ unsigned const Modulator::m_nspd = 2048 + 512; // 22.5 WPM
|
||||
Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent)
|
||||
: AudioDevice {parent}
|
||||
, m_stream {nullptr}
|
||||
, m_quickClose {false}
|
||||
, m_phi {0.0}
|
||||
, m_framesSent {0}
|
||||
, m_frameRate {frameRate}
|
||||
@ -34,21 +35,27 @@ Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObjec
|
||||
, m_state {Idle}
|
||||
, m_tuning {false}
|
||||
, m_muted {false}
|
||||
, m_cwLevel {false}
|
||||
{
|
||||
qsrand (QDateTime::currentMSecsSinceEpoch()); // Initialize random seed
|
||||
qsrand (QDateTime::currentMSecsSinceEpoch()); // Initialize random
|
||||
// seed
|
||||
}
|
||||
|
||||
void Modulator::start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, QAudioOutput * stream, Channel channel, bool synchronize, double dBSNR)
|
||||
void Modulator::start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, SoundOutput * stream, Channel channel, bool synchronize, double dBSNR)
|
||||
{
|
||||
Q_ASSERT (stream);
|
||||
|
||||
// Time according to this computer which becomes our base time
|
||||
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
|
||||
// qDebug () << "Modulator: Using soft keying for CW is " << SOFT_KEYING;;
|
||||
|
||||
if (m_state != Idle)
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
|
||||
// qDebug () << "Modulator: Using soft keying for CW is " << SOFT_KEYING;;
|
||||
m_quickClose = false;
|
||||
|
||||
m_symbolsLength = symbolsLength;
|
||||
m_framesSent = 0;
|
||||
@ -83,25 +90,38 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol, unsigned
|
||||
m_stream = stream;
|
||||
if (m_stream)
|
||||
{
|
||||
m_stream->start (this);
|
||||
m_stream->restart (this);
|
||||
}
|
||||
}
|
||||
|
||||
void Modulator::stop ()
|
||||
void Modulator::tune (bool newState)
|
||||
{
|
||||
if (m_stream)
|
||||
m_tuning = newState;
|
||||
if (!m_tuning)
|
||||
{
|
||||
m_stream->reset ();
|
||||
stop (true);
|
||||
}
|
||||
}
|
||||
|
||||
void Modulator::stop (bool quick)
|
||||
{
|
||||
m_quickClose = quick;
|
||||
close ();
|
||||
}
|
||||
|
||||
void Modulator::close ()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
if (m_quickClose)
|
||||
{
|
||||
m_stream->reset ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stream->stop ();
|
||||
}
|
||||
}
|
||||
if (m_state != Idle)
|
||||
{
|
||||
Q_EMIT stateChanged ((m_state = Idle));
|
||||
@ -138,6 +158,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
|
||||
}
|
||||
|
||||
Q_EMIT stateChanged ((m_state = Active));
|
||||
m_cwLevel = false;
|
||||
m_ramp = 0; // prepare for CW wave shaping
|
||||
}
|
||||
// fall through
|
||||
@ -153,39 +174,41 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
|
||||
qint64 framesGenerated (0);
|
||||
|
||||
while (samples != end) {
|
||||
j = (m_ic - ic0) / m_nspd + 1; // symbol of this sample
|
||||
bool level {static_cast<bool> (icw[j])};
|
||||
|
||||
m_phi += m_dphi;
|
||||
if (m_phi > m_twoPi) m_phi -= m_twoPi;
|
||||
|
||||
qint16 sample ((SOFT_KEYING ? qAbs (m_ramp - 1) :
|
||||
(m_ramp ? 32767 : 0)) * qSin (m_phi));
|
||||
|
||||
j = (m_ic - ic0 - 1) / m_nspd + 1;
|
||||
bool l0 (icw[j] && icw[j] <= 1); // first element treated specially as it's a count
|
||||
j = (m_ic - ic0) / m_nspd + 1;
|
||||
|
||||
if ((m_ramp != 0 && m_ramp != std::numeric_limits<qint16>::min ()) ||
|
||||
!!icw[j] != l0) {
|
||||
if (!!icw[j] != l0) {
|
||||
Q_ASSERT (m_ramp == 0 || m_ramp == std::numeric_limits<qint16>::min ());
|
||||
}
|
||||
m_ramp += RAMP_INCREMENT; // ramp
|
||||
}
|
||||
|
||||
if (j < NUM_CW_SYMBOLS) { // stop condition
|
||||
// if (!m_ramp && !icw[j])
|
||||
// {
|
||||
// sample = 0;
|
||||
// }
|
||||
|
||||
if (j < NUM_CW_SYMBOLS) // stop condition
|
||||
{
|
||||
samples = load (postProcessSample (sample), samples);
|
||||
++framesGenerated;
|
||||
++m_ic;
|
||||
}
|
||||
|
||||
// adjust ramp
|
||||
if ((m_ramp != 0 && m_ramp != std::numeric_limits<qint16>::min ()) || level != m_cwLevel)
|
||||
{
|
||||
// either ramp has terminated at max/min or direction
|
||||
// has changed
|
||||
m_ramp += RAMP_INCREMENT; // ramp
|
||||
}
|
||||
|
||||
// if (m_cwLevel != level)
|
||||
// {
|
||||
// qDebug () << "@m_ic:" << m_ic << "icw[" << j << "] =" << icw[j] << "@" << framesGenerated << "in numFrames:" << numFrames;
|
||||
// }
|
||||
|
||||
m_cwLevel = level;
|
||||
}
|
||||
|
||||
if (j > static_cast<unsigned> (icw[0]))
|
||||
{
|
||||
close ();
|
||||
Q_EMIT stateChanged ((m_state = Idle));
|
||||
}
|
||||
|
||||
m_framesSent += framesGenerated;
|
||||
@ -202,6 +225,8 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
|
||||
for (unsigned i = 0; i < numFrames; ++i) {
|
||||
isym = m_tuning ? 0 : m_ic / (4.0 * m_nsps); //Actual fsample=48000
|
||||
if (isym != m_isym0) {
|
||||
// qDebug () << "@m_ic:" << m_ic << "itone[" << isym << "] =" << itone[isym] << "@" << i << "in numFrames:" << numFrames;
|
||||
|
||||
if(m_toneSpacing==0.0) {
|
||||
toneFrequency0=m_frequency + itone[isym]*baud;
|
||||
} else {
|
||||
@ -251,7 +276,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
|
||||
}
|
||||
|
||||
Q_ASSERT (Idle == m_state);
|
||||
close ();
|
||||
//close ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
#ifndef MODULATOR_HPP__
|
||||
#define MODULATOR_HPP__
|
||||
|
||||
#include <QAudio>
|
||||
|
||||
#include "AudioDevice.hpp"
|
||||
|
||||
class QAudioOutput;
|
||||
class SoundOutput;
|
||||
|
||||
//
|
||||
// Input device that generates PCM audio frames that encode a message
|
||||
@ -30,9 +32,9 @@ public:
|
||||
bool isActive () const {return m_state != Idle;}
|
||||
void setWide9(double d1, double d2) {m_toneSpacing=d1; m_fSpread=d2;}
|
||||
|
||||
Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, QAudioOutput *, Channel = Mono, bool synchronize = true, double dBSNR = 99.);
|
||||
Q_SLOT void stop ();
|
||||
Q_SLOT void tune (bool newState = true) {m_tuning = newState;}
|
||||
Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, SoundOutput *, Channel = Mono, bool synchronize = true, double dBSNR = 99.);
|
||||
Q_SLOT void stop (bool quick = false);
|
||||
Q_SLOT void tune (bool newState = true);
|
||||
Q_SLOT void mute (bool newState = true) {m_muted = newState;}
|
||||
Q_SLOT void setFrequency (unsigned newFrequency) {m_frequency = newFrequency;}
|
||||
Q_SIGNAL void stateChanged (ModulatorState) const;
|
||||
@ -47,7 +49,8 @@ protected:
|
||||
private:
|
||||
qint16 postProcessSample (qint16 sample) const;
|
||||
|
||||
QAudioOutput * m_stream;
|
||||
SoundOutput * m_stream;
|
||||
bool m_quickClose;
|
||||
|
||||
unsigned m_symbolsLength;
|
||||
|
||||
@ -75,6 +78,7 @@ private:
|
||||
bool volatile m_muted;
|
||||
bool m_addNoise;
|
||||
|
||||
bool m_cwLevel;
|
||||
unsigned m_ic;
|
||||
unsigned m_isym0;
|
||||
qint16 m_ramp;
|
||||
|
@ -31,8 +31,8 @@
|
||||
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
int itone[NUM_JT65_SYMBOLS]; //Audio tones for all Tx symbols
|
||||
int icw[NUM_CW_SYMBOLS]; //Dits for CW ID
|
||||
int volatile itone[NUM_JT65_SYMBOLS]; //Audio tones for all Tx symbols
|
||||
int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID
|
||||
|
||||
int outBufSize;
|
||||
int rc;
|
||||
@ -267,30 +267,27 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
|
||||
font.setWeight(75);
|
||||
ui->readFreq->setFont(font);
|
||||
|
||||
connect(&m_guiTimer, SIGNAL(timeout()), this, SLOT(guiUpdate()));
|
||||
connect(&m_guiTimer, &QTimer::timeout, this, &MainWindow::guiUpdate);
|
||||
m_guiTimer.start(100); //Don't change the 100 ms!
|
||||
|
||||
ptt0Timer = new QTimer(this);
|
||||
ptt0Timer->setSingleShot(true);
|
||||
connect (ptt0Timer, &QTimer::timeout, &m_modulator, &Modulator::stop);
|
||||
connect(ptt0Timer, SIGNAL(timeout()), this, SLOT(stopTx2()));
|
||||
connect(ptt0Timer, &QTimer::timeout, this, &MainWindow::stopTx2);
|
||||
ptt1Timer = new QTimer(this);
|
||||
ptt1Timer->setSingleShot(true);
|
||||
connect(ptt1Timer, SIGNAL(timeout()), this, SLOT(startTx2()));
|
||||
connect(ptt1Timer, &QTimer::timeout, this, &MainWindow::startTx2);
|
||||
|
||||
logQSOTimer = new QTimer(this);
|
||||
logQSOTimer->setSingleShot(true);
|
||||
connect(logQSOTimer, SIGNAL(timeout()), this, SLOT(on_logQSOButton_clicked()));
|
||||
connect(logQSOTimer, &QTimer::timeout, this, &MainWindow::on_logQSOButton_clicked);
|
||||
|
||||
tuneButtonTimer= new QTimer(this);
|
||||
tuneButtonTimer->setSingleShot(true);
|
||||
connect (tuneButtonTimer, &QTimer::timeout, &m_modulator, &Modulator::stop);
|
||||
connect(tuneButtonTimer, SIGNAL(timeout()), this,
|
||||
SLOT(on_stopTxButton_clicked()));
|
||||
connect(tuneButtonTimer, &QTimer::timeout, this, &MainWindow::on_stopTxButton_clicked);
|
||||
|
||||
killFileTimer = new QTimer(this);
|
||||
killFileTimer->setSingleShot(true);
|
||||
connect(killFileTimer, SIGNAL(timeout()), this, SLOT(killFile()));
|
||||
connect(killFileTimer, &QTimer::timeout, this, &MainWindow::killFile);
|
||||
|
||||
m_auto=false;
|
||||
m_waterfallAvg = 1;
|
||||
@ -502,7 +499,10 @@ void MainWindow::readSettings()
|
||||
}
|
||||
|
||||
m_settings->beginGroup("Common");
|
||||
morse_(const_cast<char *> (m_config.my_callsign ().toLatin1().constData()),icw,&m_ncw,m_config.my_callsign ().length());
|
||||
morse_(const_cast<char *> (m_config.my_callsign ().toLatin1().constData())
|
||||
, const_cast<int *> (icw)
|
||||
, &m_ncw
|
||||
, m_config.my_callsign ().length());
|
||||
m_mode=m_settings->value("Mode","JT9").toString();
|
||||
m_modeTx=m_settings->value("ModeTx","JT9").toString();
|
||||
if(m_modeTx.mid(0,3)=="JT9") ui->pbTxMode->setText("Tx JT9 @");
|
||||
@ -1484,8 +1484,20 @@ void MainWindow::guiUpdate()
|
||||
// ba2msg(ba,msgsent);
|
||||
int len1=22;
|
||||
int ichk=0,itext=0;
|
||||
if(m_modeTx=="JT9") genjt9_(message,&ichk,msgsent,itone,&itext,len1,len1);
|
||||
if(m_modeTx=="JT65") gen65_(message,&ichk,msgsent,itone,&itext,len1,len1);
|
||||
if(m_modeTx=="JT9") genjt9_(message
|
||||
, &ichk
|
||||
, msgsent
|
||||
, const_cast<int *> (itone)
|
||||
, &itext
|
||||
, len1
|
||||
, len1);
|
||||
if(m_modeTx=="JT65") gen65_(message
|
||||
, &ichk
|
||||
, msgsent
|
||||
, const_cast<int *> (itone)
|
||||
, &itext
|
||||
, len1
|
||||
, len1);
|
||||
msgsent[22]=0;
|
||||
QString t=QString::fromLatin1(msgsent);
|
||||
if(m_tune) t="TUNE";
|
||||
@ -2164,7 +2176,13 @@ void MainWindow::msgtype(QString t, QLineEdit* tx) //msgtype()
|
||||
QByteArray s=t.toUpper().toLocal8Bit();
|
||||
ba2msg(s,message);
|
||||
int ichk=1,itext=0;
|
||||
genjt9_(message,&ichk,msgsent,itone,&itext,len1,len1);
|
||||
genjt9_(message
|
||||
, &ichk
|
||||
, msgsent
|
||||
, const_cast<int *> (itone)
|
||||
, &itext
|
||||
, len1
|
||||
, len1);
|
||||
msgsent[22]=0;
|
||||
bool text=false;
|
||||
if(itext!=0) text=true;
|
||||
@ -2829,11 +2847,11 @@ void MainWindow::transmit (double snr)
|
||||
{
|
||||
if (m_modeTx == "JT65")
|
||||
{
|
||||
Q_EMIT sendMessage (NUM_JT65_SYMBOLS, 4096.0 * 12000.0 / 11025.0, m_txFreq - m_XIT, m_soundOutput.stream (), m_config.audio_output_channel (), true, snr);
|
||||
Q_EMIT sendMessage (NUM_JT65_SYMBOLS, 4096.0 * 12000.0 / 11025.0, m_txFreq - m_XIT, &m_soundOutput, m_config.audio_output_channel (), true, snr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_EMIT sendMessage (NUM_JT9_SYMBOLS, m_nsps, m_txFreq - m_XIT, m_soundOutput.stream (), m_config.audio_output_channel (), true, snr);
|
||||
Q_EMIT sendMessage (NUM_JT9_SYMBOLS, m_nsps, m_txFreq - m_XIT, &m_soundOutput, m_config.audio_output_channel (), true, snr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@
|
||||
#define NUM_CW_SYMBOLS 250
|
||||
#define TX_SAMPLE_RATE 48000
|
||||
|
||||
extern int itone[NUM_JT65_SYMBOLS]; //Audio tones for all Tx symbols
|
||||
extern int icw[NUM_CW_SYMBOLS]; //Dits for CW ID
|
||||
extern int volatile itone[NUM_JT65_SYMBOLS]; //Audio tones for all Tx symbols
|
||||
extern int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID
|
||||
|
||||
|
||||
//--------------------------------------------------------------- MainWindow
|
||||
@ -48,7 +48,6 @@ class WideGraph;
|
||||
class LogQSO;
|
||||
class Transceiver;
|
||||
class Astro;
|
||||
class QAudioOutput;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
@ -190,9 +189,9 @@ private:
|
||||
Q_SIGNAL void finished () const;
|
||||
Q_SIGNAL void muteAudioOutput (bool = true) const;
|
||||
Q_SIGNAL void transmitFrequency (unsigned) const;
|
||||
Q_SIGNAL void endTransmitMessage () const;
|
||||
Q_SIGNAL void endTransmitMessage (bool quick = false) const;
|
||||
Q_SIGNAL void tune (bool = true) const;
|
||||
Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, QAudioOutput *, AudioDevice::Channel = AudioDevice::Mono, bool synchronize = true, double dBSNR = 99.) const;
|
||||
Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, SoundOutput *, AudioDevice::Channel = AudioDevice::Mono, bool synchronize = true, double dBSNR = 99.) const;
|
||||
Q_SIGNAL void outAttenuationChanged (qreal) const;
|
||||
|
||||
private:
|
||||
|
@ -2106,6 +2106,9 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="toolTip">
|
||||
<string>Adjust Tx audio level</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -2122,7 +2125,7 @@ p, li { white-space: pre-wrap; }
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>0</number>
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
36
soundout.cpp
36
soundout.cpp
@ -50,6 +50,8 @@ void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels,
|
||||
{
|
||||
Q_ASSERT (0 < channels && channels < 3);
|
||||
|
||||
m_msBuffered = msBuffered;
|
||||
|
||||
QAudioFormat format (device.preferredFormat ());
|
||||
|
||||
format.setChannelCount (channels);
|
||||
@ -74,6 +76,11 @@ void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels,
|
||||
connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged);
|
||||
|
||||
// qDebug() << "A" << m_volume << m_stream->notifyInterval();
|
||||
}
|
||||
|
||||
void SoundOutput::restart (QIODevice * source)
|
||||
{
|
||||
Q_ASSERT (m_stream);
|
||||
|
||||
//
|
||||
// This buffer size is critical since for proper sound streaming. If
|
||||
@ -88,8 +95,11 @@ void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels,
|
||||
// we have to set this before every start on the stream because the
|
||||
// Windows implementation seems to forget the buffer size after a
|
||||
// stop.
|
||||
m_stream->setBufferSize (m_stream->format().bytesForDuration((msBuffered ? msBuffered : MS_BUFFERED) * 1000));
|
||||
// qDebug() << "B" << m_stream->bufferSize() << m_stream->periodSize() << m_stream->notifyInterval();
|
||||
m_stream->setBufferSize (m_stream->format().bytesForDuration((m_msBuffered ? m_msBuffered : MS_BUFFERED) * 1000));
|
||||
// qDebug() << "B" << m_stream->bufferSize() <<
|
||||
// m_stream->periodSize() << m_stream->notifyInterval();
|
||||
|
||||
m_stream->start (source);
|
||||
}
|
||||
|
||||
void SoundOutput::suspend ()
|
||||
@ -110,6 +120,24 @@ void SoundOutput::resume ()
|
||||
}
|
||||
}
|
||||
|
||||
void SoundOutput::reset ()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
m_stream->reset ();
|
||||
audioError ();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundOutput::stop ()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
m_stream->stop ();
|
||||
audioError ();
|
||||
}
|
||||
}
|
||||
|
||||
qreal SoundOutput::attenuation () const
|
||||
{
|
||||
return -(10. * qLn (m_volume) / qLn (10.));
|
||||
@ -117,7 +145,7 @@ qreal SoundOutput::attenuation () const
|
||||
|
||||
void SoundOutput::setAttenuation (qreal a)
|
||||
{
|
||||
Q_ASSERT (0. <= a && a <= 99.);
|
||||
Q_ASSERT (0. <= a && a <= 999.);
|
||||
m_volume = qPow (10., -a / 10.);
|
||||
// qDebug () << "SoundOut: attn = " << a << ", vol = " << m_volume;
|
||||
if (m_stream)
|
||||
@ -137,6 +165,8 @@ void SoundOutput::resetAttenuation ()
|
||||
|
||||
void SoundOutput::handleStateChanged (QAudio::State newState)
|
||||
{
|
||||
// qDebug () << "SoundOutput::handleStateChanged: newState:" << newState;
|
||||
|
||||
switch (newState)
|
||||
{
|
||||
case QAudio::IdleState:
|
||||
|
11
soundout.h
11
soundout.h
@ -17,13 +17,21 @@ class SoundOutput
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
SoundOutput ()
|
||||
: m_msBuffered {0u}
|
||||
, m_volume {1.0}
|
||||
{
|
||||
}
|
||||
|
||||
qreal attenuation () const;
|
||||
QAudioOutput * stream () {return m_stream.data ();}
|
||||
|
||||
public Q_SLOTS:
|
||||
void setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered = 0u);
|
||||
void restart (QIODevice *);
|
||||
void suspend ();
|
||||
void resume ();
|
||||
void reset ();
|
||||
void stop ();
|
||||
void setAttenuation (qreal); /* unsigned */
|
||||
void resetAttenuation (); /* to zero */
|
||||
|
||||
@ -39,6 +47,7 @@ private Q_SLOTS:
|
||||
|
||||
private:
|
||||
QScopedPointer<QAudioOutput> m_stream;
|
||||
unsigned m_msBuffered;
|
||||
qreal m_volume;
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#cmakedefine01 WSJT_TRACE_CAT_POLLS
|
||||
#cmakedefine01 WSJT_HAMLIB_TRACE
|
||||
#cmakedefine01 WSJT_STANDARD_FILE_LOCATIONS
|
||||
#cmakedefine01 WSJT_SOFT_KEYING
|
||||
|
||||
#define WSJTX_STRINGIZE1(x) #x
|
||||
#define WSJTX_STRINGIZE(x) WSJTX_STRINGIZE1(x)
|
||||
|
Loading…
Reference in New Issue
Block a user