Rearranged sequencing of audio streams and devices.

The code  was starting streams linked  to closed devices which  may be
causing issues on  the Mac version.  I have refactored  to ensure that
devices are always opened before related audio streams are started.

Made .h C++ headers emacs friendly.

Removed some code in the MainWindow  contructor that read the log file
but failed to check if the file exists and didn't do anything with the
data anyway.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3977 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2014-04-03 19:29:13 +00:00
parent 542c85d8f6
commit 581691befb
23 changed files with 566 additions and 566 deletions

View File

@ -13,11 +13,11 @@ namespace
} static_initializer;
}
bool AudioDevice::open (OpenMode mode, Channel channel)
bool AudioDevice::initialize (OpenMode mode, Channel channel)
{
m_channel = channel;
// ensure we are unbuffered
// open and ensure we are unbuffered if possible
return QIODevice::open (mode | QIODevice::Unbuffered);
}

View File

@ -24,7 +24,7 @@ public:
return "both" == s ? Both : "right" == s ? Right : "left" == s ? Left : Mono;
}
bool open (OpenMode mode, Channel channel);
bool initialize (OpenMode mode, Channel channel);
bool isSequential () const {return true;}

View File

@ -30,6 +30,11 @@ public:
bool isMonitoring () const {return m_monitoring;}
Q_SLOT void setMonitoring (bool newState) {m_monitoring = newState; m_bufferPos = 0;}
Q_SLOT bool reset ();
Q_SIGNAL void framesWritten (qint64) const;
protected:
qint64 readData (char * /* data */, qint64 /* maxSize */)
{
@ -39,14 +44,6 @@ protected:
qint64 writeData (char const * data, qint64 maxSize);
private:
// these are private because we want thread safety, must be called via Qt queued connections
Q_SLOT void open (AudioDevice::Channel channel = Mono) {AudioDevice::open (QIODevice::WriteOnly, channel);}
Q_SLOT void setMonitoring (bool newState) {m_monitoring = newState; m_bufferPos = 0;}
Q_SLOT bool reset ();
Q_SLOT void close () {AudioDevice::close ();}
Q_SIGNAL void framesWritten (qint64) const;
void clear (); // discard buffer contents
unsigned secondInPeriod () const;

View File

@ -24,26 +24,30 @@ double const Modulator::m_twoPi = 2.0 * 3.141592653589793238462;
// m_nspd=3072; //18.75 WPM
unsigned const Modulator::m_nspd = 2048 + 512; // 22.5 WPM
Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, \
QObject * parent)
: AudioDevice (parent)
, m_phi (0.0)
, m_framesSent (0)
, m_frameRate (frameRate)
, m_period (periodLengthInSeconds)
, m_state (Idle)
, m_tuning (false)
, m_muted (false)
Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent)
: AudioDevice {parent}
, m_stream {nullptr}
, m_phi {0.0}
, m_framesSent {0}
, m_frameRate {frameRate}
, m_period {periodLengthInSeconds}
, m_state {Idle}
, m_tuning {false}
, m_muted {false}
{
qsrand (QDateTime::currentMSecsSinceEpoch()); // Initialize random seed
}
void Modulator::open (unsigned symbolsLength, double framesPerSymbol, \
unsigned frequency, Channel channel, bool synchronize, double dBSNR)
void Modulator::start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, QAudioOutput * stream, Channel channel, bool synchronize, double dBSNR)
{
// Time according to this computer which becomes our base time
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
if (m_state != Idle)
{
stop ();
}
// qDebug () << "Modulator: Using soft keying for CW is " << SOFT_KEYING;;
m_symbolsLength = symbolsLength;
@ -73,9 +77,36 @@ void Modulator::open (unsigned symbolsLength, double framesPerSymbol, \
// qDebug () << "Modulator: starting at " << m_ic / m_frameRate << " sec, sending " << m_silentFrames << " silent frames";
AudioDevice::open (QIODevice::ReadOnly, channel);
initialize (QIODevice::ReadOnly, channel);
Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ?
Synchronizing : Active));
m_stream = stream;
if (m_stream)
{
m_stream->start (this);
}
}
void Modulator::stop ()
{
if (m_stream)
{
m_stream->reset ();
}
close ();
}
void Modulator::close ()
{
if (m_stream)
{
m_stream->stop ();
}
if (m_state != Idle)
{
Q_EMIT stateChanged ((m_state = Idle));
}
AudioDevice::close ();
}
qint64 Modulator::readData (char * data, qint64 maxSize)
@ -152,8 +183,9 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
}
}
if (j > static_cast<unsigned> (icw[0])) {
Q_EMIT stateChanged ((m_state = Idle));
if (j > static_cast<unsigned> (icw[0]))
{
close ();
}
m_framesSent += framesGenerated;
@ -212,7 +244,6 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
m_framesSent += numFrames;
return numFrames * bytesPerFrame ();
}
Q_EMIT stateChanged ((m_state = Idle));
// fall through
case Idle:
@ -220,6 +251,8 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
}
Q_ASSERT (Idle == m_state);
close ();
return 0;
}

View File

@ -3,11 +3,7 @@
#include "AudioDevice.hpp"
#ifdef UNIX
# define NUM_CHANNELS 2
#else
# define NUM_CHANNELS 1
#endif
class QAudioOutput;
//
// Input device that generates PCM audio frames that encode a message
@ -16,20 +12,17 @@
// Output can be muted while underway, preserving waveform timing when
// transmission is resumed.
//
class Modulator : public AudioDevice
class Modulator
: public AudioDevice
{
Q_OBJECT;
Q_PROPERTY (unsigned frequency READ frequency WRITE setFrequency);
Q_PROPERTY (bool tuning READ isTuning WRITE tune);
Q_PROPERTY (bool muted READ isMuted WRITE mute);
public:
enum ModulatorState {Synchronizing, Active, Idle};
Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent = 0);
Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent = nullptr);
Q_SLOT void open (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, AudioDevice::Channel, bool synchronize = true, double dBSNR = 99.);
void close () override;
bool isTuning () const {return m_tuning;}
bool isMuted () const {return m_muted;}
@ -37,6 +30,13 @@ 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 mute (bool newState = true) {m_muted = newState;}
Q_SLOT void setFrequency (unsigned newFrequency) {m_frequency = newFrequency;}
Q_SIGNAL void stateChanged (ModulatorState) const;
protected:
qint64 readData (char * data, qint64 maxSize);
qint64 writeData (char const * /* data */, qint64 /* maxSize */)
@ -44,24 +44,11 @@ protected:
return -1; // we don't consume data
}
private:
/* private because we epect to run in a thread and don't want direct
C++ calls made, instead they must be invoked via the Qt
signal/slot mechanism which is thread safe */
Q_SLOT void close ()
{
Q_EMIT stateChanged ((m_state = Idle));
AudioDevice::close ();
}
Q_SLOT void tune (bool newState = true) {m_tuning = newState;}
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;
private:
qint16 postProcessSample (qint16 sample) const;
QAudioOutput * m_stream;
unsigned m_symbolsLength;
static double const m_twoPi;
@ -80,8 +67,8 @@ private:
qint64 m_silentFrames;
qint64 m_framesSent;
int m_frameRate;
int m_period;
unsigned m_frameRate;
unsigned m_period;
ModulatorState volatile m_state;
bool volatile m_tuning;

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef ABOUTDLG_H
#define ABOUTDLG_H

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
/*
* Class to handle the formatted string as returned from the fortran decoder
*

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef DISPLAYTEXT_H
#define DISPLAYTEXT_H

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef GETFILE_H
#define GETFILE_H
#include <QString>

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef LogQSO_H
#define LogQSO_H

View File

@ -36,7 +36,6 @@ int icw[NUM_CW_SYMBOLS]; //Dits for CW ID
int outBufSize;
int rc;
qint32 g_COMportOpen;
qint32 g_iptt;
static int nc1=1;
wchar_t buffer[256];
@ -134,37 +133,30 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
connect (m_audioThread, &QThread::finished, m_audioThread, &QThread::deleteLater); // disposal
// hook up sound output stream slots & signals
connect (this, SIGNAL (startAudioOutputStream (QAudioDeviceInfo const&, unsigned, unsigned)), &m_soundOutput, SLOT (startStream (QAudioDeviceInfo const&, unsigned, unsigned)));
connect (this, SIGNAL (stopAudioOutputStream ()), &m_soundOutput, SLOT (stopStream ()));
connect (this, &MainWindow::initializeAudioOutputStream, &m_soundOutput, &SoundOutput::setFormat);
connect (&m_soundOutput, &SoundOutput::error, this, &MainWindow::showSoundOutError);
// connect (&m_soundOutput, &SoundOutput::status, this, &MainWindow::showStatusMessage);
connect (this, SIGNAL (outAttenuationChanged (qreal)), &m_soundOutput, SLOT (setAttenuation (qreal)));
connect (this, &MainWindow::outAttenuationChanged, &m_soundOutput, &SoundOutput::setAttenuation);
// hook up Modulator slots
connect (this, SIGNAL (muteAudioOutput (bool)), &m_modulator, SLOT (mute (bool)));
connect (this, SIGNAL(transmitFrequency (unsigned)), &m_modulator, SLOT (setFrequency (unsigned)));
connect (this, SIGNAL (endTransmitMessage ()), &m_modulator, SLOT (close ()));
connect (this, SIGNAL (tune (bool)), &m_modulator, SLOT (tune (bool)));
connect (this, SIGNAL (sendMessage (unsigned, double, unsigned, AudioDevice::Channel, bool, double))
, &m_modulator, SLOT (open (unsigned, double, unsigned, AudioDevice::Channel, bool, double)));
connect (this, &MainWindow::muteAudioOutput, &m_modulator, &Modulator::mute);
connect (this, &MainWindow::transmitFrequency, &m_modulator, &Modulator::setFrequency);
connect (this, &MainWindow::endTransmitMessage, &m_modulator, &Modulator::stop);
connect (this, &MainWindow::tune, &m_modulator, &Modulator::tune);
connect (this, &MainWindow::sendMessage, &m_modulator, &Modulator::start);
// hook up the audio input stream
connect (this, SIGNAL (startAudioInputStream (QAudioDeviceInfo const&, unsigned, int, QIODevice *, unsigned))
, &m_soundInput, SLOT (start (QAudioDeviceInfo const&, unsigned, int, QIODevice *, unsigned)));
connect (this, SIGNAL (stopAudioInputStream ()), &m_soundInput, SLOT (stop ()));
connect (this, &MainWindow::startAudioInputStream, &m_soundInput, &SoundInput::start);
connect (this, &MainWindow::finished, &m_soundInput, &SoundInput::stop);
connect (this, &MainWindow::finished, this, &MainWindow::close);
connect(&m_soundInput, SIGNAL (error (QString)), this, SLOT (showSoundInError (QString)));
// connect(&m_soundInput, SIGNAL(status(QString)), this, SLOT(showStatusMessage(QString)));
connect(&m_soundInput, &SoundInput::error, this, &MainWindow::showSoundInError);
// connect(&m_soundInput, &SoundInput::status, this, &MainWindow::showStatusMessage);
// hook up the detector
connect (this, SIGNAL (startDetector (AudioDevice::Channel)), &m_detector, SLOT (open (AudioDevice::Channel)));
connect (this, SIGNAL (detectorSetMonitoring (bool)), &m_detector, SLOT (setMonitoring (bool)));
connect (this, SIGNAL (detectorClose ()), &m_detector, SLOT (close ()));
connect(&m_detector, SIGNAL (framesWritten (qint64)), this, SLOT (dataSink (qint64)));
connect (this, &MainWindow::detectorSetMonitoring, &m_detector, &Detector::setMonitoring);
connect(&m_detector, &Detector::framesWritten, this, &MainWindow::dataSink);
// setup the waterfall
connect(m_wideGraph.data (), SIGNAL(freezeDecode2(int)),this,
@ -281,7 +273,7 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
ptt0Timer = new QTimer(this);
ptt0Timer->setSingleShot(true);
connect (ptt0Timer, SIGNAL (timeout ()), &m_modulator, SLOT (close ()));
connect (ptt0Timer, &QTimer::timeout, &m_modulator, &Modulator::stop);
connect(ptt0Timer, SIGNAL(timeout()), this, SLOT(stopTx2()));
ptt1Timer = new QTimer(this);
ptt1Timer->setSingleShot(true);
@ -293,7 +285,7 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
tuneButtonTimer= new QTimer(this);
tuneButtonTimer->setSingleShot(true);
connect (tuneButtonTimer, SIGNAL (timeout ()), &m_modulator, SLOT (close ()));
connect (tuneButtonTimer, &QTimer::timeout, &m_modulator, &Modulator::stop);
connect(tuneButtonTimer, SIGNAL(timeout()), this,
SLOT(on_stopTxButton_clicked()));
@ -328,7 +320,6 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
m_inGain=0;
m_dataAvailable=false;
g_iptt=0;
g_COMportOpen=0;
m_secID=0;
m_blankLine=false;
m_decodedText2=false;
@ -423,26 +414,13 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
watcher2 = new QFutureWatcher<void>;
connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished()));
Q_EMIT startDetector (m_config.audio_input_channel ());
Q_EMIT startAudioInputStream (m_config.audio_input_device (), AudioDevice::Mono == m_config.audio_input_channel () ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor);
Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, &m_detector, m_downSampleFactor, m_config.audio_input_channel ());
Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered);
Q_EMIT transmitFrequency (m_txFreq - m_XIT);
Q_EMIT muteAudioOutput (false);
// Create "m_worked", a dictionary of all calls in wsjtx.log
QFile f(m_config.data_path ().absoluteFilePath ("wsjtx.log"));
f.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&f);
QString line,t,callsign;
for(int i=0; i<99999; i++) {
line=in.readLine();
if(line.length()<=0) break;
t=line.mid(18,12);
callsign=t.mid(0,t.indexOf(","));
}
f.close();
t="UTC dB DT Freq Message";
auto t = "UTC dB DT Freq Message";
ui->decodedTextLabel->setText(t);
ui->decodedTextLabel2->setText(t);
@ -450,10 +428,8 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
ui->label_9->setStyleSheet("QLabel{background-color: #aabec8}");
ui->label_10->setStyleSheet("QLabel{background-color: #aabec8}");
ui->labUTC->setStyleSheet( \
"QLabel { background-color : black; color : yellow; }");
ui->labDialFreq->setStyleSheet( \
"QLabel { background-color : black; color : yellow; }");
ui->labUTC->setStyleSheet("QLabel { background-color : black; color : yellow; }");
ui->labDialFreq->setStyleSheet("QLabel { background-color : black; color : yellow; }");
m_config.transceiver_online (true);
qsy (m_lastMonitoredFrequency);
@ -665,14 +641,10 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog
if(m_mode=="JT9W-1") m_toneSpacing=pow(2,m_config.jt9w_bw_mult ())*12000.0/6912.0;
if(m_config.restart_audio_input ()) {
Q_EMIT stopAudioInputStream ();
Q_EMIT detectorClose ();
Q_EMIT startDetector (m_config.audio_input_channel ());
Q_EMIT startAudioInputStream (m_config.audio_input_device (), AudioDevice::Mono == m_config.audio_input_channel () ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor);
Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, &m_detector, m_downSampleFactor, m_config.audio_input_channel ());
}
if(m_config.restart_audio_output ()) {
Q_EMIT stopAudioOutputStream ();
Q_EMIT startAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered);
Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered);
}
auto_tx_label->setText (m_config.quick_call () ? "Tx-Enable Armed" : "Tx-Enable Disarmed");
@ -709,7 +681,6 @@ void MainWindow::on_monitorButton_clicked (bool checked)
}
Q_EMIT detectorSetMonitoring (checked);
// Q_EMIT startAudioInputStream (m_params.audio_input_device, AudioDevice::Mono == m_params.audio_input_channel ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor);
}
else
{
@ -1431,7 +1402,6 @@ void MainWindow::guiUpdate()
static char msgsent[29];
static int nsendingsh=0;
static int giptt00=-1;
static int gcomport00=-1;
static double onAirFreq0=0.0;
QString rt;
@ -1670,9 +1640,8 @@ void MainWindow::guiUpdate()
m_sec0=nsec;
}
if(g_iptt!=giptt00 or g_COMportOpen!=gcomport00) {
if(g_iptt!=giptt00) {
giptt00=g_iptt;
gcomport00=g_COMportOpen;
}
iptt0=g_iptt;
@ -1706,7 +1675,6 @@ void MainWindow::startTx2()
void MainWindow::stopTx()
{
Q_EMIT endTransmitMessage ();
Q_EMIT stopAudioOutputStream ();
m_transmitting=false;
if ("JT9+JT65" == m_mode) ui->pbTxMode->setEnabled(true);
g_iptt=0;
@ -2859,13 +2827,12 @@ 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_config.audio_output_channel (), true, snr);
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);
}
else
{
Q_EMIT sendMessage (NUM_JT9_SYMBOLS, m_nsps, m_txFreq - m_XIT, m_config.audio_output_channel (), true, snr);
Q_EMIT sendMessage (NUM_JT9_SYMBOLS, m_nsps, m_txFreq - m_XIT, m_soundOutput.stream (), m_config.audio_output_channel (), true, snr);
}
Q_EMIT startAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered);
}
void MainWindow::on_outAttenuation_valueChanged (int a)

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#ifdef QT5
@ -13,6 +14,7 @@
#include <QScopedPointer>
#include "soundin.h"
#include "AudioDevice.hpp"
#include "soundout.h"
#include "commons.h"
#include "Radio.hpp"
@ -46,6 +48,7 @@ class WideGraph;
class LogQSO;
class Transceiver;
class Astro;
class QAudioOutput;
class MainWindow : public QMainWindow
{
@ -175,11 +178,10 @@ private slots:
private:
void enable_DXCC_entity (bool on);
Q_SIGNAL void startAudioOutputStream (QAudioDeviceInfo, unsigned channels, unsigned msBuffered) const;
Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo, unsigned channels, unsigned msBuffered) const;
Q_SIGNAL void stopAudioOutputStream () const;
Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor) const;
Q_SIGNAL void stopAudioInputStream () const;
Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel) const;
Q_SIGNAL void startDetector (AudioDevice::Channel) const;
Q_SIGNAL void detectorSetMonitoring (bool) const;
@ -190,7 +192,7 @@ private:
Q_SIGNAL void transmitFrequency (unsigned) const;
Q_SIGNAL void endTransmitMessage () const;
Q_SIGNAL void tune (bool = true) const;
Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, AudioDevice::Channel, bool synchronize = true, double dBSNR = 99.) 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 outAttenuationChanged (qreal) const;
private:

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef METERWIDGET_H
#define METERWIDGET_H

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
///////////////////////////////////////////////////////////////////////////
// Some code in this file and accompanying files is based on work by
// Moe Wheatley, AE4Y, released under the "Simplified BSD License".

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef PSK_REPORTER_H
#define PSK_REPORTER_H

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef SIGNALMETER_H
#define SIGNALMETER_H

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef SLEEP_H
#define SLEEP_H
#include <qthread.h>

View File

@ -40,15 +40,16 @@ bool SoundInput::audioError () const
return result;
}
void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor)
void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel channel)
{
Q_ASSERT (0 < channels && channels < 3);
Q_ASSERT (sink);
stop ();
m_sink = sink;
QAudioFormat format (device.preferredFormat());
format.setChannelCount (channels);
format.setChannelCount (AudioDevice::Mono == channel ? 1 : 2);
format.setCodec ("audio/pcm");
format.setSampleRate (12000 * downSampleFactor);
format.setSampleType (QAudioFormat::SignedInt);
@ -74,10 +75,18 @@ void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int fr
}
connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged);
m_stream->setBufferSize (m_stream->format ().bytesForFrames (framesPerBuffer));
if (sink->initialize (QIODevice::WriteOnly, channel))
{
m_stream->start (sink);
audioError ();
}
else
{
Q_EMIT error (tr ("Failed to initialize audio sink device"));
}
}
void SoundInput::handleStateChanged (QAudio::State newState) const
{
@ -115,8 +124,14 @@ void SoundInput::stop()
m_stream->stop ();
}
m_stream.reset ();
if (m_sink)
{
m_sink->close ();
}
}
SoundInput::~SoundInput ()
{
stop ();
}

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef SOUNDIN_H__
#define SOUNDIN_H__
@ -6,9 +7,10 @@
#include <QScopedPointer>
#include <QAudioInput>
#include "AudioDevice.hpp"
class QAudioDeviceInfo;
class QAudioInput;
class QIODevice;
// Gets audio data from sound sample source and passes it to a sink device
class SoundInput
@ -17,27 +19,30 @@ class SoundInput
Q_OBJECT;
public:
SoundInput (QObject * parent = 0)
: QObject (parent)
SoundInput (QObject * parent = nullptr)
: QObject {parent}
, m_sink {nullptr}
{
}
~SoundInput ();
// sink must exist from the start call to any following stop () call
Q_SLOT void start(QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor);
// sink must exist from the start call until the next start call or
// stop call
Q_SLOT void start(QAudioDeviceInfo const&, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel = AudioDevice::Mono);
Q_SLOT void stop ();
private:
Q_SIGNAL void error (QString message) const;
Q_SIGNAL void status (QString message) const;
private:
// used internally
Q_SLOT void handleStateChanged (QAudio::State) const;
bool audioError () const;
QScopedPointer<QAudioInput> m_stream;
AudioDevice * m_sink;
};
#endif

View File

@ -54,8 +54,7 @@ SoundOutput::SoundOutput (QIODevice * source)
Q_ASSERT (source);
}
void SoundOutput::startStream (QAudioDeviceInfo const& device, \
unsigned channels, unsigned msBuffered)
void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered)
{
Q_ASSERT (0 < channels && channels < 3);
@ -83,8 +82,7 @@ void SoundOutput::startStream (QAudioDeviceInfo const& device, \
m_stream->setVolume (m_volume);
m_stream->setNotifyInterval(100);
connect (m_stream.data(), &QAudioOutput::stateChanged, this, \
&SoundOutput::handleStateChanged);
connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged);
m_currentDevice = device;
// qDebug() << "A" << m_volume << m_stream->notifyInterval();
@ -103,12 +101,8 @@ void SoundOutput::startStream (QAudioDeviceInfo const& device, \
// 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));
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->start (m_source);
audioError ();
}
void SoundOutput::suspend ()
@ -154,15 +148,6 @@ void SoundOutput::resetAttenuation ()
}
}
void SoundOutput::stopStream ()
{
if (m_stream)
{
m_stream->stop ();
audioError ();
}
}
void SoundOutput::handleStateChanged (QAudio::State newState)
{
switch (newState)

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef SOUNDOUT_H__
#define SOUNDOUT_H__
@ -24,15 +25,12 @@ class SoundOutput
bool isRunning() const {return m_active;}
qreal attenuation () const;
QAudioOutput * stream () {return m_stream.data ();}
private Q_SLOTS:
/* private because we expect to run in a thread and don't want direct
C++ calls made, instead they must be invoked via the Qt
signal/slot mechanism which is thread safe */
void startStream (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered = 0u);
public Q_SLOTS:
void setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered = 0u);
void suspend ();
void resume ();
void stopStream ();
void setAttenuation (qreal); /* unsigned */
void resetAttenuation (); /* to zero */

View File

@ -1,3 +1,4 @@
// -*- Mode: C++ -*-
#ifndef WIDEGRAPH_H
#define WIDEGRAPH_H