kopia lustrzana https://gitlab.com/eliggett/wfview
Add experimental audio converter
rodzic
5bd29096e5
commit
78f16b7cff
|
@ -0,0 +1,293 @@
|
|||
#include "audioconverter.h"
|
||||
#include "logcategories.h"
|
||||
#include "ulaw.h"
|
||||
|
||||
audioConverter::audioConverter(){
|
||||
}
|
||||
|
||||
bool audioConverter::init(QAudioFormat inFormat, QAudioFormat outFormat, quint8 opusComplexity, quint8 resampleQuality)
|
||||
{
|
||||
|
||||
this->inFormat = inFormat;
|
||||
this->outFormat = outFormat;
|
||||
this->opusComplexity = opusComplexity;
|
||||
this->resampleQuality = resampleQuality;
|
||||
|
||||
qInfo(logAudioConverter) << "Starting audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inFormat.codec() << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outFormat.codec() << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
|
||||
|
||||
|
||||
if (inFormat.codec() == "audio/opus")
|
||||
{
|
||||
// Create instance of opus decoder
|
||||
int opus_err = 0;
|
||||
opusDecoder = opus_decoder_create(inFormat.sampleRate(), inFormat.channelCount(), &opus_err);
|
||||
qInfo(logAudioConverter()) << "Creating opus decoder: " << opus_strerror(opus_err);
|
||||
}
|
||||
|
||||
if (outFormat.codec() == "audio/opus")
|
||||
{
|
||||
// Create instance of opus encoder
|
||||
int opus_err = 0;
|
||||
opusEncoder = opus_encoder_create(outFormat.sampleRate(), outFormat.channelCount(), OPUS_APPLICATION_AUDIO, &opus_err);
|
||||
opus_encoder_ctl(opusEncoder, OPUS_SET_LSB_DEPTH(16));
|
||||
opus_encoder_ctl(opusEncoder, OPUS_SET_INBAND_FEC(1));
|
||||
opus_encoder_ctl(opusEncoder, OPUS_SET_DTX(1));
|
||||
opus_encoder_ctl(opusEncoder, OPUS_SET_PACKET_LOSS_PERC(5));
|
||||
opus_encoder_ctl(opusEncoder, OPUS_SET_COMPLEXITY(opusComplexity)); // Reduce complexity to maybe lower CPU?
|
||||
qInfo(logAudioConverter()) << "Creating opus encoder: " << opus_strerror(opus_err);
|
||||
}
|
||||
|
||||
if (inFormat.sampleRate() != outFormat.sampleRate())
|
||||
{
|
||||
int resampleError = 0;
|
||||
unsigned int ratioNum;
|
||||
unsigned int ratioDen;
|
||||
// Sample rate conversion required.
|
||||
resampler = wf_resampler_init(outFormat.channelCount(), inFormat.sampleRate(), outFormat.sampleRate(), resampleQuality, &resampleError);
|
||||
wf_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
|
||||
resampleRatio = static_cast<double>(ratioDen) / ratioNum;
|
||||
qInfo(logAudioConverter()) << "wf_resampler_init() returned: " << resampleError << " resampleRatio: " << resampleRatio;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
audioConverter::~audioConverter()
|
||||
{
|
||||
|
||||
qInfo(logAudioConverter) << "Closing audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inFormat.codec() << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outFormat.codec() << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
|
||||
|
||||
if (opusEncoder != Q_NULLPTR) {
|
||||
qInfo(logAudioConverter()) << "Destroying opus encoder";
|
||||
opus_encoder_destroy(opusEncoder);
|
||||
}
|
||||
|
||||
if (opusDecoder != Q_NULLPTR) {
|
||||
qInfo(logAudioConverter()) << "Destroying opus decoder";
|
||||
opus_decoder_destroy(opusDecoder);
|
||||
}
|
||||
|
||||
if (resampler != Q_NULLPTR) {
|
||||
speex_resampler_destroy(resampler);
|
||||
qDebug(logAudioConverter()) << "Resampler closed";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool audioConverter::convert(audioPacket audio)
|
||||
{
|
||||
|
||||
if (inFormat.codec() == "audio/opus")
|
||||
{
|
||||
unsigned char* in = (unsigned char*)audio.data.data();
|
||||
|
||||
//Decode the frame.
|
||||
int nSamples = opus_packet_get_nb_samples(in, audio.data.size(), inFormat.sampleRate());
|
||||
if (nSamples == -1) {
|
||||
// No opus data yet?
|
||||
return false;
|
||||
}
|
||||
QByteArray outPacket(nSamples * sizeof(float) * inFormat.channelCount(), (char)0xff); // Preset the output buffer size.
|
||||
float* out = (float*)outPacket.data();
|
||||
|
||||
if (audio.seq > lastAudioSequence + 1) {
|
||||
nSamples = opus_decode_float(opusDecoder, Q_NULLPTR, 0, out, nSamples, 1);
|
||||
}
|
||||
else {
|
||||
nSamples = opus_decode_float(opusDecoder, in, audio.data.size(), out, nSamples, 0);
|
||||
}
|
||||
audio.data.clear();
|
||||
audio.data = outPacket; // Replace incoming data with converted.
|
||||
}
|
||||
else if (inFormat.codec() == "audio/PCMU")
|
||||
{
|
||||
// Current packet is "technically" 8bit so need to create a new buffer that is 16bit
|
||||
QByteArray outPacket((int)audio.data.length() * 2, (char)0xff);
|
||||
qint16* out = (qint16*)outPacket.data();
|
||||
for (int f = 0; f < audio.data.length(); f++)
|
||||
{
|
||||
*out++ = ulaw_decode[(quint8)audio.data[f]];
|
||||
}
|
||||
audio.data.clear();
|
||||
audio.data = outPacket; // Replace incoming data with converted.
|
||||
// Make sure that sample size/type is set correctly
|
||||
}
|
||||
|
||||
Eigen::VectorXf samplesF;
|
||||
|
||||
if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 32)
|
||||
{
|
||||
Eigen::Ref<VectorXint32> samplesI = Eigen::Map<VectorXint32>(reinterpret_cast<qint32*>(audio.data.data()), audio.data.size() / int(sizeof(qint32)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint32>::max());
|
||||
}
|
||||
else if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 16)
|
||||
{
|
||||
Eigen::Ref<VectorXint16> samplesI = Eigen::Map<VectorXint16>(reinterpret_cast<qint16*>(audio.data.data()), audio.data.size() / int(sizeof(qint16)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint16>::max());
|
||||
}
|
||||
else if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 8)
|
||||
{
|
||||
Eigen::Ref<VectorXint8> samplesI = Eigen::Map<VectorXint8>(reinterpret_cast<qint8*>(audio.data.data()), audio.data.size() / int(sizeof(qint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint8>::max());;
|
||||
}
|
||||
else if (inFormat.sampleType() == QAudioFormat::UnSignedInt && inFormat.sampleSize() == 8)
|
||||
{
|
||||
Eigen::Ref<VectorXuint8> samplesI = Eigen::Map<VectorXuint8>(reinterpret_cast<quint8*>(audio.data.data()), audio.data.size() / int(sizeof(quint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<quint8>::max());;
|
||||
}
|
||||
else if (inFormat.sampleType() == QAudioFormat::Float) {
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(audio.data.data()), audio.data.size() / int(sizeof(float)));
|
||||
}
|
||||
else
|
||||
{
|
||||
qInfo(logAudio()) << "Unsupported Sample Type:" << inFormat.sampleType() << "Size:" << inFormat.sampleSize();
|
||||
}
|
||||
|
||||
|
||||
audio.amplitude = samplesF.array().abs().maxCoeff();
|
||||
// Set the volume
|
||||
samplesF *= audio.volume;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
samplesF is now an Eigen Vector of the current samples in float format
|
||||
The next step is to convert to the correct number of channels in outFormat.channelCount()
|
||||
*/
|
||||
|
||||
|
||||
if (inFormat.channelCount() == 2 && outFormat.channelCount() == 1) {
|
||||
// If we need to drop one of the audio channels, do it now
|
||||
Eigen::VectorXf samplesTemp(samplesF.size() / 2);
|
||||
samplesTemp = Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesF.data(), samplesF.size() / 2);
|
||||
samplesF = samplesTemp;
|
||||
}
|
||||
else if (inFormat.channelCount() == 1 && outFormat.channelCount() == 2) {
|
||||
// Convert mono to stereo if required
|
||||
Eigen::VectorXf samplesTemp(samplesF.size() * 2);
|
||||
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data(), samplesF.size()) = samplesF;
|
||||
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data() + 1, samplesF.size()) = samplesF;
|
||||
samplesF = samplesTemp;
|
||||
}
|
||||
|
||||
/*
|
||||
Next step is to resample (if needed)
|
||||
*/
|
||||
|
||||
if (resampler != Q_NULLPTR && resampleRatio != 1.0)
|
||||
{
|
||||
quint32 outFrames = ((samplesF.size() / outFormat.channelCount()) * resampleRatio);
|
||||
quint32 inFrames = (samplesF.size() / outFormat.channelCount());
|
||||
QByteArray outPacket(outFrames * outFormat.channelCount() * sizeof(float), (char)0xff); // Preset the output buffer size.
|
||||
const float* in = (float*)samplesF.data();
|
||||
float* out = (float*)outPacket.data();
|
||||
|
||||
int err = 0;
|
||||
if (outFormat.channelCount() == 1) {
|
||||
err = wf_resampler_process_float(resampler, 0, in, &inFrames, out, &outFrames);
|
||||
}
|
||||
else {
|
||||
err = wf_resampler_process_interleaved_float(resampler, in, &inFrames, out, &outFrames);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
qInfo(logAudioConverter()) << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
|
||||
}
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(outPacket.data()), outPacket.size() / int(sizeof(float)));
|
||||
}
|
||||
|
||||
/*
|
||||
Output is Opus so encode it now
|
||||
*/
|
||||
|
||||
if (outFormat.codec() == "audio/opus")
|
||||
{
|
||||
float* in = (float*)samplesF.data();
|
||||
QByteArray outPacket(1275, (char)0xff); // Preset the output buffer size to MAXIMUM possible Opus frame size
|
||||
unsigned char* out = (unsigned char*)outPacket.data();
|
||||
|
||||
int nbBytes = opus_encode_float(opusEncoder, in, (samplesF.size() / outFormat.channelCount()), out, outPacket.length());
|
||||
if (nbBytes < 0)
|
||||
{
|
||||
qInfo(logAudioConverter()) << "Opus encode failed:" << opus_strerror(nbBytes) << "Num Samples:" << samplesF.size();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
outPacket.resize(nbBytes);
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(outPacket.data()), outPacket.size() / int(sizeof(float)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Now convert back into the output format required
|
||||
*/
|
||||
audio.data.clear();
|
||||
|
||||
if (outFormat.sampleType() == QAudioFormat::UnSignedInt && outFormat.sampleSize() == 8)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<quint8>::max());
|
||||
VectorXuint8 samplesI = samplesITemp.cast<quint8>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(quint8)));
|
||||
}
|
||||
if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 8)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint8>::max());
|
||||
VectorXint8 samplesI = samplesITemp.cast<qint8>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint8)));
|
||||
}
|
||||
if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 16)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint16>::max());
|
||||
VectorXint16 samplesI = samplesITemp.cast<qint16>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint16)));
|
||||
}
|
||||
else if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 32)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint32>::max());
|
||||
VectorXint32 samplesI = samplesITemp.cast<qint32>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32)));
|
||||
}
|
||||
else if (outFormat.sampleType() == QAudioFormat::Float)
|
||||
{
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesF.data()), int(samplesF.size()) * int(sizeof(float)));
|
||||
}
|
||||
else {
|
||||
qInfo(logAudio()) << "Unsupported Sample Type:" << outFormat.sampleType();
|
||||
}
|
||||
|
||||
/*
|
||||
As we currently don't have a float based uLaw encoder, this must be done
|
||||
after all other conversion has taken place.
|
||||
*/
|
||||
|
||||
if (outFormat.codec() == "audio/PCMU")
|
||||
{
|
||||
QByteArray outPacket((int)audio.data.length() / 2, (char)0xff);
|
||||
qint16* in = (qint16*)audio.data.data();
|
||||
for (int f = 0; f < outPacket.length(); f++)
|
||||
{
|
||||
qint16 sample = *in++;
|
||||
int sign = (sample >> 8) & 0x80;
|
||||
if (sign)
|
||||
sample = (short)-sample;
|
||||
if (sample > cClip)
|
||||
sample = cClip;
|
||||
sample = (short)(sample + cBias);
|
||||
int exponent = (int)MuLawCompressTable[(sample >> 7) & 0xFF];
|
||||
int mantissa = (sample >> (exponent + 3)) & 0x0F;
|
||||
int compressedByte = ~(sign | (exponent << 4) | mantissa);
|
||||
outPacket[f] = (quint8)compressedByte;
|
||||
}
|
||||
audio.data.clear();
|
||||
audio.data = outPacket; // Copy output packet back to input buffer.
|
||||
|
||||
}
|
||||
|
||||
emit converted(audio);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef AUDIOCONVERTER_H
|
||||
#define AUDIOCONVERTER_H
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
#include <QTime>
|
||||
#include <QMap>
|
||||
#include <QDebug>
|
||||
#include <QAudioFormat>
|
||||
|
||||
/* Opus and Eigen */
|
||||
#ifdef Q_OS_WIN
|
||||
#include "opus.h"
|
||||
#include <Eigen/Eigen>
|
||||
#else
|
||||
#include "opus/opus.h"
|
||||
#include <eigen3/Eigen/Eigen>
|
||||
#endif
|
||||
|
||||
#include "resampler/speex_resampler.h"
|
||||
|
||||
#include "packettypes.h"
|
||||
|
||||
struct audioPacket {
|
||||
quint32 seq;
|
||||
QTime time;
|
||||
quint16 sent;
|
||||
QByteArray data;
|
||||
quint8 guid[GUIDLEN];
|
||||
float amplitude;
|
||||
qreal volume = 1.0;
|
||||
};
|
||||
|
||||
class audioConverter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
audioConverter();
|
||||
~audioConverter();
|
||||
|
||||
public slots:
|
||||
bool init(QAudioFormat inFormat, QAudioFormat outFormat, quint8 opusComplexity, quint8 resampleQuality);
|
||||
bool convert(audioPacket audio);
|
||||
|
||||
signals:
|
||||
void converted(audioPacket audio);
|
||||
|
||||
protected:
|
||||
QAudioFormat inFormat;
|
||||
QAudioFormat outFormat;
|
||||
OpusEncoder* opusEncoder = Q_NULLPTR;
|
||||
OpusDecoder* opusDecoder = Q_NULLPTR;
|
||||
SpeexResamplerState* resampler = Q_NULLPTR;
|
||||
quint8 opusComplexity;
|
||||
quint8 resampleQuality = 4;
|
||||
double resampleRatio=1.0; // Default resample ratio is 1:1
|
||||
quint32 lastAudioSequence;
|
||||
};
|
||||
|
||||
|
||||
// Various audio handling functions declared inline
|
||||
|
||||
typedef Eigen::Matrix<quint8, Eigen::Dynamic, 1> VectorXuint8;
|
||||
typedef Eigen::Matrix<qint8, Eigen::Dynamic, 1> VectorXint8;
|
||||
typedef Eigen::Matrix<qint16, Eigen::Dynamic, 1> VectorXint16;
|
||||
typedef Eigen::Matrix<qint32, Eigen::Dynamic, 1> VectorXint32;
|
||||
|
||||
#endif
|
505
audiohandler.cpp
505
audiohandler.cpp
|
@ -31,18 +31,9 @@ audioHandler::~audioHandler()
|
|||
audioOutput = Q_NULLPTR;
|
||||
}
|
||||
|
||||
|
||||
if (resampler != Q_NULLPTR) {
|
||||
speex_resampler_destroy(resampler);
|
||||
qDebug(logAudio()) << "Resampler closed";
|
||||
}
|
||||
if (encoder != Q_NULLPTR) {
|
||||
qInfo(logAudio()) << "Destroying opus encoder";
|
||||
opus_encoder_destroy(encoder);
|
||||
}
|
||||
if (decoder != Q_NULLPTR) {
|
||||
qInfo(logAudio()) << "Destroying opus decoder";
|
||||
opus_decoder_destroy(decoder);
|
||||
if (converterThread != Q_NULLPTR) {
|
||||
converterThread->quit();
|
||||
converterThread->wait();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,12 +49,15 @@ bool audioHandler::init(audioSetup setupIn)
|
|||
0x08 PCM 2ch 8bit
|
||||
0x10 PCM 2ch 16bit
|
||||
0x20 uLaw 2ch 8bit
|
||||
0x40 Opus 1ch
|
||||
0x80 Opus 2ch
|
||||
*/
|
||||
|
||||
setup = setupIn;
|
||||
setup.format.setChannelCount(1);
|
||||
setup.format.setSampleSize(8);
|
||||
setup.format.setSampleType(QAudioFormat::UnSignedInt);
|
||||
setup.format.setCodec("audio/pcm");
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "audio handler starting:" << setup.name;
|
||||
|
||||
if (setup.port.isNull())
|
||||
|
@ -76,6 +70,7 @@ bool audioHandler::init(audioSetup setupIn)
|
|||
setup.ulaw = true;
|
||||
setup.format.setSampleSize(16);
|
||||
setup.format.setSampleType(QAudioFormat::SignedInt);
|
||||
setup.format.setCodec("audio/PCMU");
|
||||
}
|
||||
|
||||
if (setup.codec == 0x08 || setup.codec == 0x10 || setup.codec == 0x20 || setup.codec == 0x80) {
|
||||
|
@ -88,7 +83,9 @@ bool audioHandler::init(audioSetup setupIn)
|
|||
}
|
||||
|
||||
if (setup.codec == 0x40 || setup.codec == 0x80) {
|
||||
setup.format.setSampleSize(32);
|
||||
setup.format.setSampleType(QAudioFormat::Float);
|
||||
setup.format.setCodec("audio/opus");
|
||||
}
|
||||
|
||||
qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name <<
|
||||
|
@ -151,51 +148,32 @@ bool audioHandler::init(audioSetup setupIn)
|
|||
|
||||
// We "hopefully" now have a valid format that is supported so try connecting
|
||||
|
||||
converter = new audioConverter();
|
||||
converterThread = new QThread(this);
|
||||
converterThread->setObjectName("audioConverter()");
|
||||
converter->moveToThread(converterThread);
|
||||
|
||||
connect(this, SIGNAL(setupConverter(QAudioFormat,QAudioFormat,quint8,quint8)), converter, SLOT(init(QAudioFormat,QAudioFormat,quint8,quint8)));
|
||||
connect(converterThread, SIGNAL(finished()), converter, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(sendToConverter(audioPacket)), converter, SLOT(convert(audioPacket)));
|
||||
converterThread->start(QThread::TimeCriticalPriority);
|
||||
|
||||
if (setup.isinput) {
|
||||
audioInput = new QAudioInput(setup.port, format, this);
|
||||
|
||||
connect(audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
|
||||
emit setupConverter(format, setup.format, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedInput(audioPacket)));
|
||||
}
|
||||
else {
|
||||
audioOutput = new QAudioOutput(setup.port, format, this);
|
||||
connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
|
||||
emit setupConverter(setup.format, format, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedOutput(audioPacket)));
|
||||
}
|
||||
|
||||
// Setup resampler and opus if they are needed.
|
||||
int resample_error = 0;
|
||||
int opus_err = 0;
|
||||
if (setup.isinput) {
|
||||
resampler = wf_resampler_init(format.channelCount(), format.sampleRate(), setup.format.sampleRate(), setup.resampleQuality, &resample_error);
|
||||
if (setup.codec == 0x40 || setup.codec == 0x80) {
|
||||
// Opus codec
|
||||
encoder = opus_encoder_create(setup.format.sampleRate(), setup.format.channelCount(), OPUS_APPLICATION_AUDIO, &opus_err);
|
||||
opus_encoder_ctl(encoder, OPUS_SET_LSB_DEPTH(16));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_INBAND_FEC(1));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_DTX(1));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_PACKET_LOSS_PERC(5));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(7)); // Reduce complexity to maybe lower CPU?
|
||||
qInfo(logAudio()) << "Creating opus encoder: " << opus_strerror(opus_err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
//resampBufs = new r8b::CFixedBuffer<double>[format.channelCount()];
|
||||
//resamps = new r8b::CPtrKeeper<r8b::CDSPResampler24*>[format.channelCount()];
|
||||
resampler = wf_resampler_init(format.channelCount(), setup.format.sampleRate(), format.sampleRate(), setup.resampleQuality, &resample_error);
|
||||
if (setup.codec == 0x40 || setup.codec == 0x80) {
|
||||
// Opus codec
|
||||
decoder = opus_decoder_create(setup.format.sampleRate(), setup.format.channelCount(), &opus_err);
|
||||
qInfo(logAudio()) << "Creating opus decoder: " << opus_strerror(opus_err);
|
||||
}
|
||||
}
|
||||
unsigned int ratioNum;
|
||||
unsigned int ratioDen;
|
||||
|
||||
wf_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
|
||||
resampleRatio = static_cast<double>(ratioDen) / ratioNum;
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "wf_resampler_init() returned: " << resample_error << " resampleRatio: " << resampleRatio;
|
||||
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "thread id" << QThread::currentThreadId();
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "thread id" << QThread::currentThreadId();
|
||||
|
||||
underTimer = new QTimer();
|
||||
underTimer->setSingleShot(true);
|
||||
|
@ -211,9 +189,10 @@ void audioHandler::start()
|
|||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "start() running";
|
||||
|
||||
if (setup.isinput) {
|
||||
audioDevice = audioInput->start();
|
||||
this->open(QIODevice::WriteOnly);
|
||||
audioInput->start(this);
|
||||
connect(audioInput, SIGNAL(destroyed()), audioDevice, SLOT(deleteLater()), Qt::UniqueConnection);
|
||||
connect(audioDevice, SIGNAL(readyRead()), this, SLOT(getNextAudioChunk()), Qt::UniqueConnection);
|
||||
//connect(audioDevice, SIGNAL(readyRead()), this, SLOT(getNextAudioChunk()), Qt::UniqueConnection);
|
||||
}
|
||||
else {
|
||||
// Buffer size must be set before audio is started.
|
||||
|
@ -249,6 +228,31 @@ void audioHandler::stop()
|
|||
audioDevice = Q_NULLPTR;
|
||||
}
|
||||
|
||||
qint64 audioHandler::readData(char* data, qint64 nBytes) {
|
||||
return nBytes;
|
||||
}
|
||||
qint64 audioHandler::writeData(const char* data, qint64 nBytes) {
|
||||
|
||||
tempBuf.data.append(data,nBytes);
|
||||
|
||||
while (tempBuf.data.length() >= format.bytesForDuration(setup.blockSize * 1000)) {
|
||||
audioPacket packet;
|
||||
packet.time = QTime::currentTime();
|
||||
packet.sent = 0;
|
||||
packet.volume = volume;
|
||||
memcpy(&packet.guid, setup.guid, GUIDLEN);
|
||||
QTime startProcessing = QTime::currentTime();
|
||||
packet.data.clear();
|
||||
packet.data = tempBuf.data.mid(0, format.bytesForDuration(setup.blockSize * 1000));
|
||||
tempBuf.data.remove(0, format.bytesForDuration(setup.blockSize * 1000));
|
||||
|
||||
emit sendToConverter(packet);
|
||||
}
|
||||
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
|
||||
void audioHandler::setVolume(unsigned char volume)
|
||||
{
|
||||
this->volume = audiopot[volume];
|
||||
|
@ -256,386 +260,77 @@ void audioHandler::setVolume(unsigned char volume)
|
|||
}
|
||||
|
||||
|
||||
void audioHandler::incomingAudio(audioPacket inPacket)
|
||||
void audioHandler::incomingAudio(audioPacket packet)
|
||||
{
|
||||
QTime startProcessing = QTime::currentTime();
|
||||
|
||||
audioPacket livePacket = inPacket;
|
||||
// Process uLaw.
|
||||
if (setup.ulaw)
|
||||
{
|
||||
// Current packet is 8bit so need to create a new buffer that is 16bit
|
||||
QByteArray outPacket((int)livePacket.data.length() * 2, (char)0xff);
|
||||
qint16* out = (qint16*)outPacket.data();
|
||||
for (int f = 0; f < livePacket.data.length(); f++)
|
||||
{
|
||||
*out++ = ulaw_decode[(quint8)livePacket.data[f]];
|
||||
}
|
||||
livePacket.data.clear();
|
||||
livePacket.data = outPacket; // Replace incoming data with converted.
|
||||
}
|
||||
packet.volume = volume;
|
||||
|
||||
|
||||
/* Opus data */
|
||||
if (setup.codec == 0x40 || setup.codec == 0x80) {
|
||||
unsigned char* in = (unsigned char*)inPacket.data.data();
|
||||
|
||||
//Decode the frame.
|
||||
int nSamples = opus_packet_get_nb_samples(in, livePacket.data.size(),setup.format.sampleRate());
|
||||
if (nSamples == -1) {
|
||||
// No opus data yet?
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray outPacket(nSamples*sizeof(float)*setup.format.channelCount(), (char)0xff); // Preset the output buffer size.
|
||||
float* out = (float*)outPacket.data();
|
||||
|
||||
if (livePacket.seq > lastSentSeq + 1) {
|
||||
nSamples = opus_decode_float(decoder, Q_NULLPTR,0, out, nSamples, 1);
|
||||
}
|
||||
else {
|
||||
nSamples = opus_decode_float(decoder, in, livePacket.data.size(), out, nSamples, 0);
|
||||
}
|
||||
|
||||
if (nSamples < 0)
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus decode failed:" << opus_strerror(nSamples) << "packet size" << livePacket.data.length();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (int(nSamples * sizeof(float) * setup.format.channelCount()) != outPacket.size())
|
||||
{
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus decoder mismatch: nBytes:" << nSamples * sizeof(float) * setup.format.channelCount() << "outPacket:" << outPacket.size();
|
||||
outPacket.resize(nSamples * sizeof(float) * setup.format.channelCount());
|
||||
}
|
||||
//qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus decoded" << livePacket.data.size() << "bytes, into" << outPacket.length() << "bytes";
|
||||
livePacket.data.clear();
|
||||
livePacket.data = outPacket; // Replace incoming data with converted.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!livePacket.data.isEmpty()) {
|
||||
|
||||
Eigen::VectorXf samplesF;
|
||||
if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 32)
|
||||
{
|
||||
Eigen::Ref<VectorXint32> samplesI = Eigen::Map<VectorXint32>(reinterpret_cast<qint32*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint32)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint32>::max());
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 16)
|
||||
{
|
||||
Eigen::Ref<VectorXint16> samplesI = Eigen::Map<VectorXint16>(reinterpret_cast<qint16*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint16)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint16>::max());
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::Ref<VectorXint8> samplesI = Eigen::Map<VectorXint8>(reinterpret_cast<qint8*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint8>::max());;
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::UnSignedInt && setup.format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::Ref<VectorXuint8> samplesI = Eigen::Map<VectorXuint8>(reinterpret_cast<quint8*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(quint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<quint8>::max());;
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::Float) {
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(float)));
|
||||
}
|
||||
else
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported Sample Type:" << format.sampleType();
|
||||
}
|
||||
|
||||
|
||||
/* samplesF is now an Eigen Vector of the current samples in float format */
|
||||
|
||||
|
||||
// Set the max amplitude found in the vector
|
||||
// Should it be before or after volume is applied?
|
||||
|
||||
amplitude = samplesF.array().abs().maxCoeff();
|
||||
// Set the volume
|
||||
samplesF *= volume;
|
||||
|
||||
|
||||
if (setup.format.channelCount() == 2 && format.channelCount() == 1) {
|
||||
// If we need to drop one of the audio channels, do it now
|
||||
Eigen::VectorXf samplesTemp(samplesF.size() / 2);
|
||||
samplesTemp = Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesF.data(), samplesF.size() / 2);
|
||||
samplesF = samplesTemp;
|
||||
}
|
||||
else if (setup.format.channelCount() == 1 && format.channelCount() == 2) {
|
||||
// Convert mono to stereo if required
|
||||
Eigen::VectorXf samplesTemp(samplesF.size() * 2);
|
||||
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data(), samplesF.size()) = samplesF;
|
||||
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data() + 1, samplesF.size()) = samplesF;
|
||||
samplesF = samplesTemp;
|
||||
}
|
||||
|
||||
// We now have format.channelCount() (native) channels of audio.
|
||||
|
||||
if (resampleRatio != 1.0) {
|
||||
|
||||
// We need to resample
|
||||
// We have a stereo 16bit stream.
|
||||
quint32 outFrames = ((samplesF.size() / format.channelCount()) * resampleRatio);
|
||||
quint32 inFrames = (samplesF.size() / format.channelCount());
|
||||
QByteArray outPacket(outFrames * format.channelCount() * sizeof(float), (char)0xff); // Preset the output buffer size.
|
||||
const float* in = (float*)samplesF.data();
|
||||
float* out = (float*)outPacket.data();
|
||||
|
||||
int err = 0;
|
||||
if (format.channelCount() == 1) {
|
||||
err = wf_resampler_process_float(resampler, 0, in, &inFrames, out, &outFrames);
|
||||
}
|
||||
else {
|
||||
err = wf_resampler_process_interleaved_float(resampler, in, &inFrames, out, &outFrames);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
|
||||
}
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(outPacket.data()), outPacket.size() / int(sizeof(float)));
|
||||
}
|
||||
|
||||
if (format.sampleType() == QAudioFormat::UnSignedInt && format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<quint8>::max());
|
||||
VectorXuint8 samplesI = samplesITemp.cast<quint8>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(quint8)));
|
||||
}
|
||||
if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint8>::max());
|
||||
VectorXint8 samplesI = samplesITemp.cast<qint8>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint8)));
|
||||
}
|
||||
if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 16)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint16>::max());
|
||||
VectorXint16 samplesI = samplesITemp.cast<qint16>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint16)));
|
||||
}
|
||||
else if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 32)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint32>::max());
|
||||
VectorXint32 samplesI = samplesITemp.cast<qint32>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32)));
|
||||
}
|
||||
else if (format.sampleType() == QAudioFormat::Float)
|
||||
{
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesF.data()), int(samplesF.size()) * int(sizeof(float)));
|
||||
}
|
||||
else {
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported Sample Type:" << format.sampleType();
|
||||
}
|
||||
|
||||
currentLatency = livePacket.time.msecsTo(QTime::currentTime()) + (format.durationForBytes(audioOutput->bufferSize()-audioOutput->bytesFree())/1000);
|
||||
if (audioDevice != Q_NULLPTR) {
|
||||
audioDevice->write(livePacket.data);
|
||||
if (lastReceived.msecsTo(QTime::currentTime()) > 100) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize << "Processing time" << startProcessing.msecsTo(QTime::currentTime());
|
||||
}
|
||||
lastReceived = QTime::currentTime();
|
||||
}
|
||||
if ((inPacket.seq > lastSentSeq + 1) && (setup.codec == 0x40 || setup.codec == 0x80)) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Attempting FEC on packet" << inPacket.seq << "as last is" << lastSentSeq;
|
||||
lastSentSeq = inPacket.seq;
|
||||
incomingAudio(inPacket); // Call myself again to run the packet a second time (FEC)
|
||||
}
|
||||
|
||||
lastSentSeq = inPacket.seq;
|
||||
}
|
||||
|
||||
emit haveLevels(getAmplitude(), setup.latency, currentLatency,isUnderrun);
|
||||
emit sendToConverter(packet);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void audioHandler::convertedOutput(audioPacket packet) {
|
||||
|
||||
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (format.durationForBytes(audioOutput->bufferSize() - audioOutput->bytesFree()) / 1000);
|
||||
if (audioDevice != Q_NULLPTR) {
|
||||
audioDevice->write(packet.data);
|
||||
if (lastReceived.msecsTo(QTime::currentTime()) > 100) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize;
|
||||
}
|
||||
lastReceived = QTime::currentTime();
|
||||
}
|
||||
|
||||
/*
|
||||
if ((packet.seq > lastSentSeq + 1) && (setup.codec == 0x40 || setup.codec == 0x80)) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Attempting FEC on packet" << packet.seq << "as last is" << lastSentSeq;
|
||||
lastSentSeq = packet.seq;
|
||||
incomingAudio(packet); // Call myself again to run the packet a second time (FEC)
|
||||
}
|
||||
*/
|
||||
|
||||
lastSentSeq = packet.seq;
|
||||
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun);
|
||||
|
||||
amplitude = packet.amplitude;
|
||||
|
||||
}
|
||||
|
||||
void audioHandler::getNextAudioChunk()
|
||||
{
|
||||
tempBuf.data.append(audioDevice->readAll());
|
||||
|
||||
while (tempBuf.data.length() >= format.bytesForDuration(setup.blockSize * 1000)) {
|
||||
audioPacket livePacket;
|
||||
livePacket.time = QTime::currentTime();
|
||||
livePacket.sent = 0;
|
||||
memcpy(&livePacket.guid, setup.guid, GUIDLEN);
|
||||
audioPacket packet;
|
||||
packet.time = QTime::currentTime();
|
||||
packet.sent = 0;
|
||||
packet.volume = volume;
|
||||
memcpy(&packet.guid, setup.guid, GUIDLEN);
|
||||
QTime startProcessing = QTime::currentTime();
|
||||
livePacket.data.clear();
|
||||
livePacket.data = tempBuf.data.mid(0, format.bytesForDuration(setup.blockSize * 1000));
|
||||
packet.data.clear();
|
||||
packet.data = tempBuf.data.mid(0, format.bytesForDuration(setup.blockSize * 1000));
|
||||
tempBuf.data.remove(0, format.bytesForDuration(setup.blockSize * 1000));
|
||||
if (livePacket.data.length() > 0)
|
||||
{
|
||||
Eigen::VectorXf samplesF;
|
||||
if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 32)
|
||||
{
|
||||
Eigen::Ref<VectorXint32> samplesI = Eigen::Map<VectorXint32>(reinterpret_cast<qint32*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint32)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint32>::max());
|
||||
}
|
||||
else if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 16)
|
||||
{
|
||||
Eigen::Ref<VectorXint16> samplesI = Eigen::Map<VectorXint16>(reinterpret_cast<qint16*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint16)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint16>::max());
|
||||
}
|
||||
else if (format.sampleType() == QAudioFormat::UnSignedInt && format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::Ref<VectorXuint8> samplesI = Eigen::Map<VectorXuint8>(reinterpret_cast<quint8*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(quint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<quint8>::max());;
|
||||
}
|
||||
else if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::Ref<VectorXint8> samplesI = Eigen::Map<VectorXint8>(reinterpret_cast<qint8*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint8>::max());;
|
||||
}
|
||||
else if (format.sampleType() == QAudioFormat::Float)
|
||||
{
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(float)));
|
||||
}
|
||||
else {
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported Sample Type:" << format.sampleType() << format.sampleSize();
|
||||
}
|
||||
|
||||
/* samplesF is now an Eigen Vector of the current samples in float format */
|
||||
|
||||
// Set the max amplitude found in the vector
|
||||
if (samplesF.size() > 0) {
|
||||
amplitude = samplesF.array().abs().maxCoeff();
|
||||
|
||||
if (resampleRatio != 1.0) {
|
||||
|
||||
// We need to resample
|
||||
// We have a stereo 16bit stream.
|
||||
quint32 outFrames = ((samplesF.size() / format.channelCount()) * resampleRatio);
|
||||
quint32 inFrames = (samplesF.size() / format.channelCount());
|
||||
|
||||
QByteArray outPacket(outFrames * format.channelCount() * sizeof(float), (char)0xff); // Preset the output buffer size.
|
||||
const float* in = (float*)samplesF.data();
|
||||
float* out = (float*)outPacket.data();
|
||||
|
||||
int err = 0;
|
||||
if (format.channelCount() == 1) {
|
||||
err = wf_resampler_process_float(resampler, 0, in, &inFrames, out, &outFrames);
|
||||
}
|
||||
else {
|
||||
err = wf_resampler_process_interleaved_float(resampler, in, &inFrames, out, &outFrames);
|
||||
}
|
||||
if (err) {
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
|
||||
}
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(outPacket.data()), outPacket.size() / int(sizeof(float)));
|
||||
}
|
||||
|
||||
// If we need to drop one of the audio channels, do it now
|
||||
if (format.channelCount() == 2 && setup.format.channelCount() == 1) {
|
||||
Eigen::VectorXf samplesTemp(samplesF.size() / 2);
|
||||
samplesTemp = Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesF.data(), samplesF.size() / 2);
|
||||
samplesF = samplesTemp;
|
||||
}
|
||||
else if (format.channelCount() == 1 && setup.format.channelCount() == 2) {
|
||||
// Convert mono to stereo if required
|
||||
Eigen::VectorXf samplesTemp(samplesF.size() * 2);
|
||||
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data(), samplesF.size()) = samplesF;
|
||||
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data() + 1, samplesF.size()) = samplesF;
|
||||
samplesF = samplesTemp;
|
||||
}
|
||||
|
||||
//qInfo(logAudio()) << "Sending audio len" << livePacket.data.length() << "remaining" << tempBuf.data.length() << "resampled" << samplesF.size();
|
||||
|
||||
if (setup.codec == 0x40 || setup.codec == 0x80)
|
||||
{
|
||||
//Are we using the opus codec?
|
||||
float* in = (float*)samplesF.data();
|
||||
|
||||
/* Encode the frame. */
|
||||
QByteArray outPacket(1275, (char)0xff); // Preset the output buffer size to MAXIMUM possible Opus frame size
|
||||
unsigned char* out = (unsigned char*)outPacket.data();
|
||||
|
||||
int nbBytes = opus_encode_float(encoder, in, (samplesF.size() / setup.format.channelCount()), out, outPacket.length());
|
||||
if (nbBytes < 0)
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus encode failed:" << opus_strerror(nbBytes) << "Num Samples:" << samplesF.size();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
outPacket.resize(nbBytes);
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(outPacket.data()), outPacket.size() / int(sizeof(float)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint8>::max());
|
||||
VectorXint8 samplesI = samplesITemp.cast<qint8>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint8)));
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::UnSignedInt && setup.format.sampleSize() == 8)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<quint8>::max());
|
||||
VectorXuint8 samplesI = samplesITemp.cast<quint8>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(quint8)));
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 16)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint16>::max());
|
||||
VectorXint16 samplesI = samplesITemp.cast<qint16>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint16)));
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 32)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint32>::max());
|
||||
VectorXint32 samplesI = samplesITemp.cast<qint32>();
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32)));
|
||||
}
|
||||
else if (setup.format.sampleType() == QAudioFormat::Float)
|
||||
{
|
||||
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesF.data()), int(samplesF.size()) * int(sizeof(float)));
|
||||
}
|
||||
else {
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported Sample Type:" << format.sampleType();
|
||||
}
|
||||
|
||||
/* Need to find a floating point uLaw encoder!*/
|
||||
if (setup.ulaw)
|
||||
{
|
||||
QByteArray outPacket((int)livePacket.data.length() / 2, (char)0xff);
|
||||
qint16* in = (qint16*)livePacket.data.data();
|
||||
for (int f = 0; f < outPacket.length(); f++)
|
||||
{
|
||||
qint16 sample = *in++;
|
||||
if (setup.ulaw) {
|
||||
int sign = (sample >> 8) & 0x80;
|
||||
if (sign)
|
||||
sample = (short)-sample;
|
||||
if (sample > cClip)
|
||||
sample = cClip;
|
||||
sample = (short)(sample + cBias);
|
||||
int exponent = (int)MuLawCompressTable[(sample >> 7) & 0xFF];
|
||||
int mantissa = (sample >> (exponent + 3)) & 0x0F;
|
||||
int compressedByte = ~(sign | (exponent << 4) | mantissa);
|
||||
outPacket[f] = (quint8)compressedByte;
|
||||
}
|
||||
}
|
||||
livePacket.data.clear();
|
||||
livePacket.data = outPacket; // Copy output packet back to input buffer.
|
||||
}
|
||||
emit haveAudioData(livePacket);
|
||||
if (lastReceived.msecsTo(QTime::currentTime()) > 100) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize << "Processing time" << startProcessing.msecsTo(QTime::currentTime());
|
||||
}
|
||||
lastReceived = QTime::currentTime();
|
||||
//ret = livePacket.data;
|
||||
}
|
||||
}
|
||||
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun);
|
||||
emit sendToConverter(packet);
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void audioHandler::convertedInput(audioPacket audio)
|
||||
{
|
||||
emit haveAudioData(audio);
|
||||
if (lastReceived.msecsTo(QTime::currentTime()) > 100) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize ;
|
||||
}
|
||||
lastReceived = QTime::currentTime();
|
||||
//ret = livePacket.data;
|
||||
amplitude = audio.amplitude;
|
||||
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun);
|
||||
}
|
||||
|
||||
void audioHandler::changeLatency(const quint16 newSize)
|
||||
{
|
||||
|
||||
|
|
|
@ -48,16 +48,14 @@
|
|||
/* Logarithmic taper for volume control */
|
||||
#include "audiotaper.h"
|
||||
|
||||
|
||||
/* Audio converter class*/
|
||||
#include "audioconverter.h"
|
||||
|
||||
|
||||
#define MULAW_BIAS 33
|
||||
#define MULAW_MAX 0x1fff
|
||||
|
||||
struct audioPacket {
|
||||
quint32 seq;
|
||||
QTime time;
|
||||
quint16 sent;
|
||||
QByteArray data;
|
||||
quint8 guid[GUIDLEN];
|
||||
};
|
||||
|
||||
struct audioSetup {
|
||||
QString name;
|
||||
|
@ -74,7 +72,7 @@ struct audioSetup {
|
|||
};
|
||||
|
||||
// For QtMultimedia, use a native QIODevice
|
||||
class audioHandler : public QObject
|
||||
class audioHandler : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -94,6 +92,8 @@ public slots:
|
|||
void changeLatency(const quint16 newSize);
|
||||
void setVolume(unsigned char volume);
|
||||
void incomingAudio(const audioPacket data);
|
||||
void convertedInput(audioPacket audio);
|
||||
void convertedOutput(audioPacket audio);
|
||||
|
||||
private slots:
|
||||
void stateChanged(QAudio::State state);
|
||||
|
@ -105,8 +105,16 @@ signals:
|
|||
void sendLatency(quint16 newSize);
|
||||
void haveAudioData(const audioPacket& data);
|
||||
void haveLevels(quint16 amplitude,quint16 latency,quint16 current,bool under);
|
||||
void setupConverter(QAudioFormat in, QAudioFormat out, quint8 opus, quint8 resamp);
|
||||
void sendToConverter(audioPacket audio);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
qint64 readData(char* data, qint64 nBytes);
|
||||
qint64 writeData(const char* data, qint64 nBytes);
|
||||
|
||||
|
||||
bool isUnderrun = false;
|
||||
bool isInitialized=false;
|
||||
bool isReady = false;
|
||||
|
@ -117,7 +125,9 @@ private:
|
|||
QIODevice* audioDevice=Q_NULLPTR;
|
||||
QAudioFormat format;
|
||||
QAudioDeviceInfo deviceInfo;
|
||||
SpeexResamplerState* resampler = Q_NULLPTR;
|
||||
|
||||
audioConverter* converter=Q_NULLPTR;
|
||||
QThread* converterThread = Q_NULLPTR;
|
||||
QTime lastReceived;
|
||||
//r8b::CFixedBuffer<double>* resampBufs;
|
||||
//r8b::CPtrKeeper<r8b::CDSPResampler24*>* resamps;
|
||||
|
@ -136,21 +146,14 @@ private:
|
|||
audioPacket tempBuf;
|
||||
quint16 currentLatency;
|
||||
float amplitude;
|
||||
qreal volume=1.0;
|
||||
qreal volume = 1.0;
|
||||
|
||||
audioSetup setup;
|
||||
|
||||
OpusEncoder* encoder=Q_NULLPTR;
|
||||
OpusDecoder* decoder=Q_NULLPTR;
|
||||
OpusEncoder* encoder = Q_NULLPTR;
|
||||
OpusDecoder* decoder = Q_NULLPTR;
|
||||
QTimer* underTimer;
|
||||
};
|
||||
|
||||
|
||||
// Various audio handling functions declared inline
|
||||
|
||||
typedef Eigen::Matrix<quint8, Eigen::Dynamic, 1> VectorXuint8;
|
||||
typedef Eigen::Matrix<qint8, Eigen::Dynamic, 1> VectorXint8;
|
||||
typedef Eigen::Matrix<qint16, Eigen::Dynamic, 1> VectorXint16;
|
||||
typedef Eigen::Matrix<qint32, Eigen::Dynamic, 1> VectorXint32;
|
||||
|
||||
#endif // AUDIOHANDLER_H
|
||||
|
|
|
@ -9,3 +9,4 @@ Q_LOGGING_CATEGORY(logUdp, "udp")
|
|||
Q_LOGGING_CATEGORY(logUdpServer, "udp.server")
|
||||
Q_LOGGING_CATEGORY(logRigCtlD, "rigctld")
|
||||
Q_LOGGING_CATEGORY(logTcpServer, "tcpserver")
|
||||
Q_LOGGING_CATEGORY(logAudioConverter, "audioconverter")
|
||||
|
|
|
@ -12,6 +12,7 @@ Q_DECLARE_LOGGING_CATEGORY(logUdp)
|
|||
Q_DECLARE_LOGGING_CATEGORY(logUdpServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logRigCtlD)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logTcpServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logAudioConverter)
|
||||
|
||||
|
||||
#if defined(Q_OS_WIN) && !defined(__PRETTY_FUNCTION__)
|
||||
|
|
376
wfview.vcxproj
376
wfview.vcxproj
|
@ -16,7 +16,8 @@
|
|||
<Keyword>QtVS_v304</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild></PropertyGroup>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
|
@ -36,7 +37,10 @@
|
|||
<IntermediateDirectory>debug\</IntermediateDirectory>
|
||||
<PrimaryOutput>wfview</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /><Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')"><Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." /></Target>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
|
||||
</Target>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
|
@ -44,8 +48,34 @@
|
|||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" /><ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')"><Import Project="$(QtMsBuild)\qt_defaults.props" /></ImportGroup><PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"><OutDir>debug\</OutDir><IntDir>debug\</IntDir><TargetName>wfview</TargetName><IgnoreImportLibrary>true</IgnoreImportLibrary></PropertyGroup><PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"><OutDir>release\</OutDir><IntDir>release\</IntDir><TargetName>wfview</TargetName><IgnoreImportLibrary>true</IgnoreImportLibrary><LinkIncremental>false</LinkIncremental></PropertyGroup><PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"><QtInstall>msvc2019</QtInstall><QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules></PropertyGroup><PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"><QtInstall>msvc2019</QtInstall><QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules></PropertyGroup><ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')"><Import Project="$(QtMsBuild)\qt.props" /></ImportGroup>
|
||||
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
|
||||
<Import Project="$(QtMsBuild)\qt_defaults.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>debug\</OutDir>
|
||||
<IntDir>debug\</IntDir>
|
||||
<TargetName>wfview</TargetName>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>release\</OutDir>
|
||||
<IntDir>release\</IntDir>
|
||||
<TargetName>wfview</TargetName>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<QtInstall>msvc2019</QtInstall>
|
||||
<QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<QtInstall>msvc2019</QtInstall>
|
||||
<QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
|
||||
<Import Project="$(QtMsBuild)\qt.props" />
|
||||
</ImportGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;release;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -59,12 +89,14 @@
|
|||
<Optimization>MaxSpeed</Optimization>
|
||||
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.2e";BUILD_WFVIEW;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX="/usr/local";GITSHORT="b510b70";HOST="wfview.org";UNAME="build";NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessToFile>false</PreprocessToFile>
|
||||
<ProgramDataBaseFileName></ProgramDataBaseFileName>
|
||||
<ProgramDataBaseFileName>
|
||||
</ProgramDataBaseFileName>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation></ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>..\opus\win32\VS2015\Win32\Release\opus.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\opus\win32\VS2015\Win32\Release;C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
@ -87,7 +119,26 @@
|
|||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2e\";BUILD_WFVIEW;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"b510b70\";HOST=\"wfview.org\";UNAME=\"build\";NDEBUG;QT_NO_DEBUG;QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc><CompilerFlavor>msvc</CompilerFlavor><Include>./$(Configuration)/moc_predefs.h</Include><ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription><DynamicSource>output</DynamicSource><QtMocDir>$(Configuration)</QtMocDir><QtMocFileName>moc_%(Filename).cpp</QtMocFileName></QtMoc><QtRcc><Compression>default</Compression><ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription><QtRccDir>$(Configuration)</QtRccDir><QtRccFileName>qrc_%(Filename).cpp</QtRccFileName></QtRcc><QtUic><ExecutionDescription>Uic'ing %(Identity)...</ExecutionDescription><QtUicDir>$(ProjectDir)</QtUicDir><QtUicFileName>ui_%(Filename).h</QtUicFileName></QtUic></ItemDefinitionGroup>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<Compression>default</Compression>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
<QtUic>
|
||||
<ExecutionDescription>Uic'ing %(Identity)...</ExecutionDescription>
|
||||
<QtUicDir>$(ProjectDir)</QtUicDir>
|
||||
<QtUicFileName>ui_%(Filename).h</QtUicFileName>
|
||||
</QtUic>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;debug;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -105,7 +156,8 @@
|
|||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation></ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>..\opus\win32\VS2015\Win32\Debug\opus.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\opus\win32\VS2015\Win32\Debug;C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
@ -126,9 +178,29 @@
|
|||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2e\";BUILD_WFVIEW;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"b510b70\";HOST=\"wfview.org\";UNAME=\"build\";QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc><CompilerFlavor>msvc</CompilerFlavor><Include>./$(Configuration)/moc_predefs.h</Include><ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription><DynamicSource>output</DynamicSource><QtMocDir>$(Configuration)</QtMocDir><QtMocFileName>moc_%(Filename).cpp</QtMocFileName></QtMoc><QtRcc><Compression>default</Compression><ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription><QtRccDir>$(Configuration)</QtRccDir><QtRccFileName>qrc_%(Filename).cpp</QtRccFileName></QtRcc><QtUic><ExecutionDescription>Uic'ing %(Identity)...</ExecutionDescription><QtUicDir>$(ProjectDir)</QtUicDir><QtUicFileName>ui_%(Filename).h</QtUicFileName></QtUic></ItemDefinitionGroup>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<Compression>default</Compression>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
<QtUic>
|
||||
<ExecutionDescription>Uic'ing %(Identity)...</ExecutionDescription>
|
||||
<QtUicDir>$(ProjectDir)</QtUicDir>
|
||||
<QtUicFileName>ui_%(Filename).h</QtUicFileName>
|
||||
</QtUic>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="aboutbox.cpp" />
|
||||
<ClCompile Include="audioconverter.cpp" />
|
||||
<ClCompile Include="audiohandler.cpp" />
|
||||
<ClCompile Include="calibrationwindow.cpp" />
|
||||
<ClCompile Include="commhandler.cpp" />
|
||||
|
@ -154,207 +226,54 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="aboutbox.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="audioconverter.h" />
|
||||
<ClInclude Include="resampler\arch.h" />
|
||||
<QtMoc Include="audiohandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="audiotaper.h" />
|
||||
<QtMoc Include="calibrationwindow.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="commhandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="freqmemory.h" />
|
||||
<ClInclude Include="logcategories.h" />
|
||||
<QtMoc Include="meter.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="packettypes.h" />
|
||||
<QtMoc Include="pttyhandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="..\qcustomplot\qcustomplot.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="qledlabel.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="repeaterattributes.h" />
|
||||
<QtMoc Include="repeatersetup.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="resampler\resample_sse.h" />
|
||||
<QtMoc Include="rigcommander.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="rigctld.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="rigidentities.h" />
|
||||
<QtMoc Include="satellitesetup.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="selectradio.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="resampler\speex_resampler.h" />
|
||||
<QtMoc Include="tcpserver.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="transceiveradjustments.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="udphandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="udpserver.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="ulaw.h" />
|
||||
<QtMoc Include="wfmain.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
<FileType>Document</FileType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
|
@ -371,121 +290,21 @@
|
|||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">release\moc_predefs.h;%(Outputs)</Outputs>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</CustomBuild>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="aboutbox.ui">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtUic>
|
||||
<QtUic Include="calibrationwindow.ui">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtUic>
|
||||
<QtUic Include="repeatersetup.ui">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtUic>
|
||||
<QtUic Include="satellitesetup.ui">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtUic>
|
||||
<QtUic Include="selectradio.ui">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtUic>
|
||||
<QtUic Include="transceiveradjustments.ui">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtUic>
|
||||
<QtUic Include="wfmain.ui">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtUic>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -519,30 +338,16 @@
|
|||
<None Include="qdarkstyle\rc\radio_unchecked_disabled.png" />
|
||||
<None Include="qdarkstyle\rc\radio_unchecked_focus.png" />
|
||||
<QtRcc Include="resources\resources.qrc">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">resources</InitFuncName><InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">resources</InitFuncName></QtRcc>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">resources</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">resources</InitFuncName>
|
||||
</QtRcc>
|
||||
<None Include="qdarkstyle\rc\right_arrow.png" />
|
||||
<None Include="qdarkstyle\rc\right_arrow_disabled.png" />
|
||||
<None Include="qdarkstyle\rc\sizegrip.png" />
|
||||
<QtRcc Include="qdarkstyle\style.qrc">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">style</InitFuncName><InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">style</InitFuncName></QtRcc>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">style</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">style</InitFuncName>
|
||||
</QtRcc>
|
||||
<None Include="qdarkstyle\style.qss" />
|
||||
<None Include="qdarkstyle\rc\stylesheet-branch-end.png" />
|
||||
<None Include="qdarkstyle\rc\stylesheet-branch-more.png" />
|
||||
|
@ -556,6 +361,9 @@
|
|||
<ItemGroup>
|
||||
<ResourceCompile Include=".\wfview_resource.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /><ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')"><Import Project="$(QtMsBuild)\qt.targets" /></ImportGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
|
@ -116,6 +116,9 @@
|
|||
<ClCompile Include="wfmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audioconverter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="aboutbox.h">
|
||||
|
@ -202,61 +205,17 @@
|
|||
<QtMoc Include="wfmain.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="audioconverter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
<Filter>Generated Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="release\moc_predefs.h.cbt">
|
||||
<Filter>Generated Files</Filter>
|
||||
</CustomBuild>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="aboutbox.ui">
|
||||
|
@ -413,6 +372,6 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="C:\Users\Phil\source\repos\wfview\wfview_resource.rc" />
|
||||
<ResourceCompile Include=".\wfview_resource.rc" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Ładowanie…
Reference in New Issue