From 78f16b7cff51b49b9a681f5344d7e89c0ec308d5 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 6 May 2022 23:10:46 +0100 Subject: [PATCH] Add experimental audio converter --- audioconverter.cpp | 293 ++++++++++++++++++++++++ audioconverter.h | 68 ++++++ audiohandler.cpp | 505 ++++++++--------------------------------- audiohandler.h | 41 ++-- logcategories.cpp | 1 + logcategories.h | 1 + wfview.vcxproj | 376 ++++++++---------------------- wfview.vcxproj.filters | 55 +---- 8 files changed, 584 insertions(+), 756 deletions(-) create mode 100644 audioconverter.cpp create mode 100644 audioconverter.h diff --git a/audioconverter.cpp b/audioconverter.cpp new file mode 100644 index 0000000..3545752 --- /dev/null +++ b/audioconverter.cpp @@ -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(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 samplesI = Eigen::Map(reinterpret_cast(audio.data.data()), audio.data.size() / int(sizeof(qint32))); + samplesF = samplesI.cast() / float(std::numeric_limits::max()); + } + else if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 16) + { + Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(audio.data.data()), audio.data.size() / int(sizeof(qint16))); + samplesF = samplesI.cast() / float(std::numeric_limits::max()); + } + else if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 8) + { + Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(audio.data.data()), audio.data.size() / int(sizeof(qint8))); + samplesF = samplesI.cast() / float(std::numeric_limits::max());; + } + else if (inFormat.sampleType() == QAudioFormat::UnSignedInt && inFormat.sampleSize() == 8) + { + Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(audio.data.data()), audio.data.size() / int(sizeof(quint8))); + samplesF = samplesI.cast() / float(std::numeric_limits::max());; + } + else if (inFormat.sampleType() == QAudioFormat::Float) { + samplesF = Eigen::Map(reinterpret_cast(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 >(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 >(samplesTemp.data(), samplesF.size()) = samplesF; + Eigen::Map >(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(reinterpret_cast(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(reinterpret_cast(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::max()); + VectorXuint8 samplesI = samplesITemp.cast(); + audio.data = QByteArray(reinterpret_cast(samplesI.data()), int(samplesI.size()) * int(sizeof(quint8))); + } + if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 8) + { + Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits::max()); + VectorXint8 samplesI = samplesITemp.cast(); + audio.data = QByteArray(reinterpret_cast(samplesI.data()), int(samplesI.size()) * int(sizeof(qint8))); + } + if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 16) + { + Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits::max()); + VectorXint16 samplesI = samplesITemp.cast(); + audio.data = QByteArray(reinterpret_cast(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::max()); + VectorXint32 samplesI = samplesITemp.cast(); + audio.data = QByteArray(reinterpret_cast(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32))); + } + else if (outFormat.sampleType() == QAudioFormat::Float) + { + audio.data = QByteArray(reinterpret_cast(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; +} + diff --git a/audioconverter.h b/audioconverter.h new file mode 100644 index 0000000..c3cc941 --- /dev/null +++ b/audioconverter.h @@ -0,0 +1,68 @@ +#ifndef AUDIOCONVERTER_H +#define AUDIOCONVERTER_H +#include +#include +#include +#include +#include +#include + +/* Opus and Eigen */ +#ifdef Q_OS_WIN +#include "opus.h" +#include +#else +#include "opus/opus.h" +#include +#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 VectorXuint8; +typedef Eigen::Matrix VectorXint8; +typedef Eigen::Matrix VectorXint16; +typedef Eigen::Matrix VectorXint32; + +#endif \ No newline at end of file diff --git a/audiohandler.cpp b/audiohandler.cpp index 4a51aab..975a5fd 100644 --- a/audiohandler.cpp +++ b/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[format.channelCount()]; - //resamps = new r8b::CPtrKeeper[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(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 samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint32))); - samplesF = samplesI.cast() / float(std::numeric_limits::max()); - } - else if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 16) - { - Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint16))); - samplesF = samplesI.cast() / float(std::numeric_limits::max()); - } - else if (setup.format.sampleType() == QAudioFormat::SignedInt && setup.format.sampleSize() == 8) - { - Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint8))); - samplesF = samplesI.cast() / float(std::numeric_limits::max());; - } - else if (setup.format.sampleType() == QAudioFormat::UnSignedInt && setup.format.sampleSize() == 8) - { - Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(quint8))); - samplesF = samplesI.cast() / float(std::numeric_limits::max());; - } - else if (setup.format.sampleType() == QAudioFormat::Float) { - samplesF = Eigen::Map(reinterpret_cast(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 >(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 >(samplesTemp.data(), samplesF.size()) = samplesF; - Eigen::Map >(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(reinterpret_cast(outPacket.data()), outPacket.size() / int(sizeof(float))); - } - - if (format.sampleType() == QAudioFormat::UnSignedInt && format.sampleSize() == 8) - { - Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits::max()); - VectorXuint8 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(samplesI.data()), int(samplesI.size()) * int(sizeof(quint8))); - } - if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 8) - { - Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits::max()); - VectorXint8 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(samplesI.data()), int(samplesI.size()) * int(sizeof(qint8))); - } - if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 16) - { - Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits::max()); - VectorXint16 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(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::max()); - VectorXint32 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32))); - } - else if (format.sampleType() == QAudioFormat::Float) - { - livePacket.data = QByteArray(reinterpret_cast(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 samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint32))); - samplesF = samplesI.cast() / float(std::numeric_limits::max()); - } - else if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 16) - { - Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint16))); - samplesF = samplesI.cast() / float(std::numeric_limits::max()); - } - else if (format.sampleType() == QAudioFormat::UnSignedInt && format.sampleSize() == 8) - { - Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(quint8))); - samplesF = samplesI.cast() / float(std::numeric_limits::max());; - } - else if (format.sampleType() == QAudioFormat::SignedInt && format.sampleSize() == 8) - { - Eigen::Ref samplesI = Eigen::Map(reinterpret_cast(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint8))); - samplesF = samplesI.cast() / float(std::numeric_limits::max());; - } - else if (format.sampleType() == QAudioFormat::Float) - { - samplesF = Eigen::Map(reinterpret_cast(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(reinterpret_cast(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 >(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 >(samplesTemp.data(), samplesF.size()) = samplesF; - Eigen::Map >(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(reinterpret_cast(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::max()); - VectorXint8 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(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::max()); - VectorXuint8 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(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::max()); - VectorXint16 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(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::max()); - VectorXint32 samplesI = samplesITemp.cast(); - livePacket.data = QByteArray(reinterpret_cast(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32))); - } - else if (setup.format.sampleType() == QAudioFormat::Float) - { - livePacket.data = QByteArray(reinterpret_cast(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) { diff --git a/audiohandler.h b/audiohandler.h index 20929d8..ea2e140 100644 --- a/audiohandler.h +++ b/audiohandler.h @@ -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* resampBufs; //r8b::CPtrKeeper* 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 VectorXuint8; -typedef Eigen::Matrix VectorXint8; -typedef Eigen::Matrix VectorXint16; -typedef Eigen::Matrix VectorXint32; - #endif // AUDIOHANDLER_H diff --git a/logcategories.cpp b/logcategories.cpp index 5719ef1..da4c6d7 100644 --- a/logcategories.cpp +++ b/logcategories.cpp @@ -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") diff --git a/logcategories.h b/logcategories.h index 5f7362a..987278d 100644 --- a/logcategories.h +++ b/logcategories.h @@ -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__) diff --git a/wfview.vcxproj b/wfview.vcxproj index 5a843a9..7a48226 100644 --- a/wfview.vcxproj +++ b/wfview.vcxproj @@ -16,7 +16,8 @@ QtVS_v304 10.0.19041.0 10.0.19041.0 - $(MSBuildProjectDirectory)\QtMsBuild + $(MSBuildProjectDirectory)\QtMsBuild + v142 @@ -36,7 +37,10 @@ debug\ wfview - + + + + @@ -44,8 +48,34 @@ - debug\debug\wfviewtruerelease\release\wfviewtruefalsemsvc2019core;network;gui;multimedia;widgets;serialport;printsupportmsvc2019core;network;gui;multimedia;widgets;serialport;printsupport - + + + + + + debug\ + debug\ + wfview + true + + + release\ + release\ + wfview + true + false + + + msvc2019 + core;network;gui;multimedia;widgets;serialport;printsupport + + + msvc2019 + core;network;gui;multimedia;widgets;serialport;printsupport + + + + .;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;release;/include;%(AdditionalIncludeDirectories) @@ -59,12 +89,14 @@ MaxSpeed _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) false - + + MultiThreadedDLL true true Level3 - true + true + ..\opus\win32\VS2015\Win32\Release\opus.lib;shell32.lib;%(AdditionalDependencies) ..\opus\win32\VS2015\Win32\Release;C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) @@ -87,7 +119,26 @@ _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) - msvc./$(Configuration)/moc_predefs.hMoc'ing %(Identity)...output$(Configuration)moc_%(Filename).cppdefaultRcc'ing %(Identity)...$(Configuration)qrc_%(Filename).cppUic'ing %(Identity)...$(ProjectDir)ui_%(Filename).h + + msvc + ./$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + $(Configuration) + moc_%(Filename).cpp + + + default + Rcc'ing %(Identity)... + $(Configuration) + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + $(ProjectDir) + ui_%(Filename).h + + .;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;debug;/include;%(AdditionalIncludeDirectories) @@ -105,7 +156,8 @@ true true Level3 - true + true + ..\opus\win32\VS2015\Win32\Debug\opus.lib;shell32.lib;%(AdditionalDependencies) ..\opus\win32\VS2015\Win32\Debug;C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) @@ -126,9 +178,29 @@ _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) - msvc./$(Configuration)/moc_predefs.hMoc'ing %(Identity)...output$(Configuration)moc_%(Filename).cppdefaultRcc'ing %(Identity)...$(Configuration)qrc_%(Filename).cppUic'ing %(Identity)...$(ProjectDir)ui_%(Filename).h + + msvc + ./$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + $(Configuration) + moc_%(Filename).cpp + + + default + Rcc'ing %(Identity)... + $(Configuration) + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + $(ProjectDir) + ui_%(Filename).h + + + @@ -154,207 +226,54 @@ - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Document true @@ -371,121 +290,21 @@ release\moc_predefs.h;%(Outputs) true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -519,30 +338,16 @@ - - - - - - - - - - resourcesresources + resources + resources + - - - - - - - - - - stylestyle + style + style + @@ -556,6 +361,9 @@ - + + + + \ No newline at end of file diff --git a/wfview.vcxproj.filters b/wfview.vcxproj.filters index b7c023b..a12a594 100644 --- a/wfview.vcxproj.filters +++ b/wfview.vcxproj.filters @@ -116,6 +116,9 @@ Source Files + + Source Files + @@ -202,61 +205,17 @@ Header Files + + Header Files + - - - - - - - - - - Generated Files Generated Files - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -413,6 +372,6 @@ - + \ No newline at end of file