Refactor SECLAL player into new threaded player class

The reason for moving the implementation out from CSoundGenerator into
its own class is, because CSoundGenerator was a very complex and
obscure class. It mixed many tasks in one place. CSelcalPlayer
is designed to play SELCALs only.

The following design changes have been made, compared to CSoundGenerator:
* Use pull mode instead of push mode. QBuffer is used as the QIODevice and
  is a wrapper around QByteArray. Therefore it is not necessary to
  implement our own QIODevice.
* Internally it uses a CThreadedSelcalPlayer to relieve the load of the
  main thread. CThreadedSelcalPlayer inherits CContinuousWorker, no
  low level QThread implementation was necessary.
* Push mode was not implemented.
* It is important that the QAudioOutput is allocated in the worker thread.
  QAudioOutput allocates internal objects, which cannot be moved to
  the worker thread.
* Data caching. The generated seclal audio data is cached.

refs #736
This commit is contained in:
Roland Winklmeier
2016-08-15 13:16:34 +02:00
committed by Mathew Sutcliffe
parent 1ff06a1174
commit 5486596335
8 changed files with 423 additions and 2 deletions

View File

@@ -0,0 +1,46 @@
/* Copyright (C) 2016
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "selcalplayer.h"
#include <QTimer>
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::PhysicalQuantities;
namespace BlackSound
{
CSelcalPlayer::CSelcalPlayer(const QAudioDeviceInfo &device, QObject *parent)
: QObject(parent),
m_threadedPlayer(this, "CSelcalPlayer", device)
{
m_threadedPlayer.start();
}
CSelcalPlayer::~CSelcalPlayer()
{
m_threadedPlayer.quitAndWait();
}
void CSelcalPlayer::play(int volume, const BlackMisc::Aviation::CSelcal &selcal)
{
if (selcal.isValid())
{
QList<CFrequency> frequencies = selcal.getFrequencies();
Q_ASSERT(frequencies.size() == 4);
const BlackMisc::PhysicalQuantities::CTime oneSec(1000.0, BlackMisc::PhysicalQuantities::CTimeUnit::ms());
CTonePair t1(frequencies.at(0), frequencies.at(1), oneSec);
CTonePair t2({}, {}, oneSec / 5.0);
CTonePair t3(frequencies.at(2), frequencies.at(3), oneSec);
QList<CTonePair> tonePairs;
tonePairs << t1 << t2 << t3;
m_threadedPlayer.play(volume, tonePairs);
}
}
}