Working (in Windows) audio output

merge-requests/9/merge
Phil Taylor 2022-04-03 20:16:52 +01:00
rodzic 8ec62fec8d
commit 389f661c79
11 zmienionych plików z 380 dodań i 175 usunięć

Wyświetl plik

@ -73,28 +73,30 @@ bool audioHandler::init(audioSetup setupIn)
*/
setup = setupIn;
setup.radioChan = 1;
setup.bits = 8;
setup.format.setChannelCount(1);
setup.format.setSampleSize(8);
setup.format.setSampleType(QAudioFormat::UnSignedInt);
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "audio handler starting:" << setup.name;
if (setup.codec == 0x01 || setup.codec == 0x20) {
setup.ulaw = true;
}
if (setup.codec == 0x08 || setup.codec == 0x10 || setup.codec == 0x20 || setup.codec == 0x80) {
setup.radioChan = 2;
setup.format.setChannelCount(2);
}
if (setup.codec == 0x04 || setup.codec == 0x10 || setup.codec == 0x40 || setup.codec == 0x80) {
setup.bits = 16;
setup.format.setSampleSize(16);
setup.format.setSampleType(QAudioFormat::SignedInt);
}
qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name <<
", bits" << setup.bits <<
", bits" << setup.format.sampleSize() <<
", codec" << setup.codec <<
", latency" << setup.latency <<
", localAFGain" << setup.localAFgain <<
", radioChan" << setup.radioChan <<
", radioChan" << setup.format.channelCount() <<
", resampleQuality" << setup.resampleQuality <<
", samplerate" << setup.samplerate <<
", samplerate" << setup.format.sampleRate() <<
", uLaw" << setup.ulaw;
@ -325,11 +327,9 @@ bool audioHandler::init(audioSetup setupIn)
else {
audioOutput = new QAudioOutput(setup.port, format, this);
#ifdef Q_OS_MAC
audioOutput->setBufferSize(chunkSize*4);
#endif
audioOutput->setBufferSize(getAudioSize(setup.latency, format));
connect(audioOutput, SIGNAL(notify()), SLOT(notified()));
//connect(audioOutput, SIGNAL(notify()), SLOT(notified()));
connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
isInitialized = true;
}
@ -339,10 +339,10 @@ bool audioHandler::init(audioSetup setupIn)
int resample_error = 0;
int opus_err = 0;
if (setup.isinput) {
resampler = wf_resampler_init(devChannels, nativeSampleRate, setup.samplerate, setup.resampleQuality, &resample_error);
resampler = wf_resampler_init(devChannels, nativeSampleRate, setup.format.sampleRate(), setup.resampleQuality, &resample_error);
if (setup.codec == 0x40 || setup.codec == 0x80) {
// Opus codec
encoder = opus_encoder_create(setup.samplerate, setup.radioChan, OPUS_APPLICATION_AUDIO, &opus_err);
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));
@ -351,10 +351,13 @@ bool audioHandler::init(audioSetup setupIn)
}
}
else {
resampler = wf_resampler_init(devChannels, setup.samplerate, this->nativeSampleRate, setup.resampleQuality, &resample_error);
//resampBufs = new r8b::CFixedBuffer<double>[format.channelCount()];
//resamps = new r8b::CPtrKeeper<r8b::CDSPResampler24*>[format.channelCount()];
resampler = wf_resampler_init(devChannels, setup.format.sampleRate(), this->nativeSampleRate, setup.resampleQuality, &resample_error);
if (setup.codec == 0x40 || setup.codec == 0x80) {
// Opus codec
decoder = opus_decoder_create(setup.samplerate, setup.radioChan, &opus_err);
decoder = opus_decoder_create(setup.format.sampleRate(), setup.format.sampleRate(), &opus_err);
qInfo(logAudio()) << "Creating opus decoder: " << opus_strerror(opus_err);
}
}
@ -400,9 +403,18 @@ void audioHandler::start()
this->open(QIODevice::ReadOnly);
#else
//this->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
this->open(QIODevice::ReadOnly);
//this->open(QIODevice::ReadOnly);
#endif
audioOutput->start(this);
audioDevice = audioOutput->start();
if (!audioDevice)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio device failed to start()";
return;
}
connect(audioOutput, &QAudioOutput::destroyed, audioDevice, &QIODevice::deleteLater, Qt::UniqueConnection);
connect(audioDevice, &QIODevice::destroyed, this, &QAudioOutput::deleteLater, Qt::UniqueConnection);
audioBuffered = true;
}
}
#endif
@ -612,45 +624,30 @@ void audioHandler::incomingAudio(audioPacket inPacket)
// Regardless of the radio stream format, the buffered audio will ALWAYS be
// 16bit sample interleaved stereo 48K (or whatever the native sample rate is)
if (inPacket.time.msecsTo(QTime::currentTime()) > 20)
{
qInfo(logUdp()) << "Audio took" << inPacket.time.msecsTo(QTime::currentTime()) << "ms to arrive!";
}
if (!isInitialized && !isReady)
{
qDebug(logAudio()) << "Packet received when stream was not ready";
return;
}
if (!audioBuffered && ringBuf->size() > ringBuf->capacity() / 2)
{
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio buffering complete, capacity:" << ringBuf->capacity() << ", used:" << ringBuf->size();
audioBuffered = true;
}
audioPacket livePacket = inPacket;
if (setup.codec == 0x40 || setup.codec == 0x80) {
/* Opus data */
unsigned char* in = (unsigned char*)inPacket.data.data();
/* Decode the frame. */
QByteArray outPacket((setup.samplerate / 50) * sizeof(qint16) * setup.radioChan, (char)0xff); // Preset the output buffer size.
QByteArray outPacket((setup.format.sampleRate() / 50) * sizeof(qint16) * setup.format.channelCount(), (char)0xff); // Preset the output buffer size.
qint16* out = (qint16*)outPacket.data();
int nSamples = opus_packet_get_nb_samples(in, livePacket.data.size(),setup.samplerate);
int nSamples = opus_packet_get_nb_samples(in, livePacket.data.size(),setup.format.sampleRate());
if (nSamples == -1) {
// No opus data yet?
return;
}
else if (nSamples != setup.samplerate / 50)
else if (nSamples != setup.format.sampleRate() / 50)
{
qInfo(logAudio()) << "Opus nSamples=" << nSamples << " expected:" << (setup.samplerate / 50);
qInfo(logAudio()) << "Opus nSamples=" << nSamples << " expected:" << (setup.format.sampleRate() / 50);
return;
}
if (livePacket.seq > lastSentSeq + 1) {
nSamples = opus_decode(decoder, in, livePacket.data.size(), out, (setup.samplerate / 50), 1);
nSamples = opus_decode(decoder, in, livePacket.data.size(), out, (setup.format.sampleRate() / 50), 1);
}
else {
nSamples = opus_decode(decoder, in, livePacket.data.size(), out, (setup.samplerate / 50), 0);
nSamples = opus_decode(decoder, in, livePacket.data.size(), out, (setup.format.sampleRate() / 50), 0);
}
if (nSamples < 0)
{
@ -658,10 +655,10 @@ void audioHandler::incomingAudio(audioPacket inPacket)
return;
}
else {
if (int(nSamples * sizeof(qint16) * setup.radioChan) != outPacket.size())
if (int(nSamples * sizeof(qint16) * setup.format.channelCount()) != outPacket.size())
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus decoder mismatch: nBytes:" << nSamples * sizeof(qint16) * setup.radioChan << "outPacket:" << outPacket.size();
outPacket.resize(nSamples * sizeof(qint16) * setup.radioChan);
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus decoder mismatch: nBytes:" << nSamples * sizeof(qint16) * setup.format.channelCount() << "outPacket:" << outPacket.size();
outPacket.resize(nSamples * sizeof(qint16) * setup.format.channelCount());
}
//qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus decoded" << livePacket.data.size() << "bytes, into" << outPacket.length() << "bytes";
livePacket.data.clear();
@ -669,105 +666,100 @@ void audioHandler::incomingAudio(audioPacket inPacket)
}
}
//qDebug(logAudio()) << "Got" << setup.bits << "bits, length" << livePacket.data.length();
// Incoming data is 8bits?
int tempAmplitude=0;
if (setup.bits == 8)
// 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 * (devChannels / setup.radioChan), (char)0xff);
QByteArray outPacket((int)livePacket.data.length() * 2, (char)0xff);
qint16* out = (qint16*)outPacket.data();
for (int f = 0; f < livePacket.data.length(); f++)
{
int samp = (quint8)livePacket.data[f];
tempAmplitude = qMax(tempAmplitude, abs(samp));
for (int g = setup.radioChan; g <= devChannels; g++)
{
if (setup.ulaw) {
*out++ = ulaw_decode[samp] * this->volume;
}
else {
*out++ = (qint16)((samp - 128) << 8) * this->volume;
}
}
*out++ = ulaw_decode[(quint8)livePacket.data[f]];
}
livePacket.data.clear();
livePacket.data = outPacket; // Replace incoming data with converted.
setup.format.setSampleSize(16);
setup.format.setSampleType(QAudioFormat::SignedInt);
// Buffer now contains 16bit signed samples.
}
else
{
// This is already a 16bit stream, do we need to convert to stereo?
if (setup.radioChan == 1 && devChannels > 1) {
// Yes
QByteArray outPacket(livePacket.data.length() * 2, (char)0xff); // Preset the output buffer size.
qint16* in = (qint16*)livePacket.data.data();
if (!livePacket.data.isEmpty()) {
Eigen::VectorXf samplesF;
if (setup.format.sampleSize() == 16)
{
VectorXint16 samplesI = Eigen::Map<VectorXint16>(reinterpret_cast<qint16*>(livePacket.data.data()), livePacket.data.size() / int(sizeof(qint16)));
samplesF = samplesI.cast<float>();
}
else
{
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());;
}
// Set the max amplitude found in the vector
amplitude = samplesF.array().abs().maxCoeff();
// Set the volume
samplesF *= volume;
// Convert mono to stereo
if (setup.format.channelCount() == 1) {
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;
}
if (format.sampleType() == QAudioFormat::SignedInt)
{
VectorXint16 samplesI = samplesF.cast<qint16>();
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint16)));
}
else
{
livePacket.data = QByteArray(reinterpret_cast<char*>(samplesF.data()), int(samplesF.size()) * int(sizeof(float)));
}
if (resampleRatio != 1.0) {
// We need to resample
// We have a stereo 16bit stream.
quint32 outFrames = ((livePacket.data.length() / 2 / devChannels) * resampleRatio);
quint32 inFrames = (livePacket.data.length() / 2 / devChannels);
QByteArray outPacket(outFrames * 4, (char)0xff); // Preset the output buffer size.
const qint16* in = (qint16*)livePacket.data.constData();
qint16* out = (qint16*)outPacket.data();
for (int f = 0; f < livePacket.data.length() / 2; f++)
{
tempAmplitude = qMax(tempAmplitude, (int)(abs(*in) / 256));
*out++ = (qint16)*in * this->volume;
*out++ = (qint16)*in++ * this->volume;
int err = 0;
err = wf_resampler_process_interleaved_int(resampler, in, &inFrames, out, &outFrames);
if (err) {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
}
livePacket.data.clear();
livePacket.data = outPacket; // Replace incoming data with converted.
}
else
{
// We already have the same number of channels so just update volume.
qint16* in = (qint16*)livePacket.data.data();
for (int f = 0; f < livePacket.data.length() / 2; f++)
{
tempAmplitude = qMax(tempAmplitude, (int)(abs(*in) / 256));
*in = *in * this->volume;
in++;
}
//qDebug(logAudio()) << "Adding packet to buffer:" << livePacket.seq << ": " << livePacket.data.length();
currentLatency = livePacket.time.msecsTo(QTime::currentTime());
audioDevice->write(livePacket.data);
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)
}
}
amplitude = tempAmplitude;
/* We now have an array of 16bit samples in the NATIVE samplerate of the radio
If the radio sample rate is below 48000, we need to resample.
*/
//qDebug(logAudio()) << "Now 16 bit stereo, length" << livePacket.data.length();
if (resampleRatio != 1.0) {
// We need to resample
// We have a stereo 16bit stream.
quint32 outFrames = ((livePacket.data.length() / 2 / devChannels) * resampleRatio);
quint32 inFrames = (livePacket.data.length() / 2 / devChannels);
QByteArray outPacket(outFrames * 4, (char)0xff); // Preset the output buffer size.
const qint16* in = (qint16*)livePacket.data.constData();
qint16* out = (qint16*)outPacket.data();
int err = 0;
err = wf_resampler_process_interleaved_int(resampler, in, &inFrames, out, &outFrames);
if (err) {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
}
livePacket.data.clear();
livePacket.data = outPacket; // Replace incoming data with converted.
}
//qDebug(logAudio()) << "Adding packet to buffer:" << livePacket.seq << ": " << livePacket.data.length();
if (!ringBuf->try_write(livePacket))
{
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Buffer full! capacity:" << ringBuf->capacity() << "length" << ringBuf->size();
while (ringBuf->try_read(inPacket)); // Empty buffer
return;
}
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;
//if (inPacket.time.msecsTo(QTime::currentTime()) > 20)
//{
//qDebug(logAudio()) << "After processing, audio took" << inPacket.time.msecsTo(QTime::currentTime()) << "ms to arrive!";
//}
return;
}
@ -776,9 +768,18 @@ void audioHandler::changeLatency(const quint16 newSize)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << setup.latency;
setup.latency = newSize;
delete ringBuf;
audioBuffered = false;
ringBuf = new wilt::Ring<audioPacket>(setup.latency + 1); // Should be customizable.
//delete ringBuf;
//audioBuffered = false;
//ringBuf = new wilt::Ring<audioPacket>(setup.latency + 1); // Should be customizable.
if (!setup.isinput) {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Current buffer size is" << audioOutput->bufferSize() << " " << getAudioDuration(audioOutput->bufferSize(), format) << "ms)";
audioOutput->stop();
audioOutput->setBufferSize(getAudioSize(setup.latency, format));
audioDevice = audioOutput->start();
connect(audioOutput, &QAudioOutput::destroyed, audioDevice, &QIODevice::deleteLater, Qt::UniqueConnection);
connect(audioDevice, &QIODevice::destroyed, this, &QAudioOutput::deleteLater, Qt::UniqueConnection);
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "New buffer size is" << audioOutput->bufferSize() << " " << getAudioDuration(audioOutput->bufferSize(), format) << "ms)";
}
}
int audioHandler::getLatency()
@ -830,7 +831,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
int tempAmplitude = 0;
// Do we need to convert mono to stereo?
if (setup.radioChan == 1 && devChannels > 1)
if (setup.format.channelCount() == 1 && devChannels > 1)
{
// Strip out right channel?
QByteArray outPacket(packet.data.length()/2, (char)0xff);
@ -857,7 +858,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
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(encoder, in, (setup.samplerate / 50), out, outPacket.length());
int nbBytes = opus_encode(encoder, in, (setup.format.sampleRate() / 50), out, outPacket.length());
if (nbBytes < 0)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Opus encode failed:" << opus_strerror(nbBytes);
@ -870,7 +871,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
}
}
else if (setup.bits == 8)
else if (setup.format.sampleSize() == 8)
{
// Do we need to convert 16-bit to 8-bit?
@ -908,7 +909,6 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Too many delayed packets, flushing buffer";
while (ringBuf->try_read(packet)); // Empty buffer
delayedPackets = 0;
audioBuffered = false;
}
}
@ -997,6 +997,6 @@ void audioHandler::stop()
quint16 audioHandler::getAmplitude()
{
return amplitude;
return *reinterpret_cast<quint16*>(&amplitude);
}

Wyświetl plik

@ -25,20 +25,10 @@
#include <QIODevice>
#endif
#include <Eigen>
#include "packettypes.h"
typedef signed short MY_TYPE;
#define FORMAT RTAUDIO_SINT16
#define SCALE 32767.0
#define LOG100 4.60517018599
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;
#include <QThread>
#include <QTimer>
@ -55,6 +45,10 @@ typedef Eigen::Matrix<qint32, Eigen::Dynamic, 1> VectorXint32;
#endif
#include "audiotaper.h"
#include <Eigen/Eigen>
//#include <r8bbase.h>
//#include <CDSPResampler.h>
#include <QDebug>
@ -75,13 +69,14 @@ struct audioPacket {
struct audioSetup {
QString name;
quint8 bits;
quint8 radioChan;
quint16 samplerate;
// quint8 bits;
// quint8 radioChan;
// quint16 samplerate;
quint16 latency;
quint8 codec;
bool ulaw;
bool ulaw = false;
bool isinput;
QAudioFormat format; // Use this for all audio APIs
#if defined(RTAUDIO) || defined(PORTAUDIO)
int port;
#else
@ -190,17 +185,22 @@ private:
#else
QAudioOutput* audioOutput=Q_NULLPTR;
QAudioInput* audioInput=Q_NULLPTR;
QIODevice* audioDevice=Q_NULLPTR;
QAudioFormat format;
QAudioDeviceInfo deviceInfo;
#endif
SpeexResamplerState* resampler = Q_NULLPTR;
//r8b::CFixedBuffer<double>* resampBufs;
//r8b::CPtrKeeper<r8b::CDSPResampler24*>* resamps;
quint16 audioLatency;
unsigned int chunkSize;
bool chunkAvailable;
quint32 lastSeq;
quint32 lastSentSeq=0;
qint64 elapsedMs = 0;
quint16 nativeSampleRate=0;
quint8 radioSampleBits;
@ -217,7 +217,7 @@ private:
volatile bool ready = false;
audioPacket tempBuf;
quint16 currentLatency;
quint16 amplitude = 0;
float amplitude;
qreal volume=1.0;
int devChannels;
audioSetup setup;
@ -225,4 +225,200 @@ private:
OpusDecoder* decoder=Q_NULLPTR;
};
// Various audio handling functions declared inline
static inline qint64 getAudioSize(qint64 timeInMs, const QAudioFormat& format)
{
qint64 value = qint64(qCeil(format.channelCount() * (format.sampleSize() / 8) * format.sampleRate() / qreal(10000) * timeInMs));
if (value % (format.channelCount() * (format.sampleSize() / 8)) != 0)
value += (format.channelCount() * (format.sampleSize() / 8) - value % (format.channelCount() * (format.sampleSize() / 8)));
return value;
}
static inline qint64 getAudioDuration(qint64 bytes, const QAudioFormat& format)
{
return qint64(qFloor(bytes / (format.channelCount() * (format.sampleSize() / 8) * format.sampleRate() / qreal(1000))));
}
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;
static inline QByteArray samplesToInt(const QByteArray& data, const QAudioFormat& supported_format)
{
QByteArray input = data;
switch (supported_format.sampleSize())
{
case 8:
{
switch (supported_format.sampleType())
{
case QAudioFormat::UnSignedInt:
{
Eigen::Ref<Eigen::VectorXf> samples_float = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(input.data()), input.size() / int(sizeof(float)));
Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits<quint8>::max());
VectorXuint8 samples_int = samples_int_tmp.cast<quint8>();
QByteArray raw = QByteArray(reinterpret_cast<char*>(samples_int.data()), int(samples_int.size()) * int(sizeof(quint8)));
return raw;
}
case QAudioFormat::SignedInt:
{
Eigen::Ref<Eigen::VectorXf> samples_float = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(input.data()), input.size() / int(sizeof(float)));
Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits<qint8>::max());
VectorXint8 samples_int = samples_int_tmp.cast<qint8>();
QByteArray raw = QByteArray(reinterpret_cast<char*>(samples_int.data()), int(samples_int.size()) * int(sizeof(qint8)));
return raw;
}
default:
break;
}
break;
}
case 16:
{
switch (supported_format.sampleType())
{
case QAudioFormat::SignedInt:
{
Eigen::Ref<Eigen::VectorXf> samples_float = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(input.data()), input.size() / int(sizeof(float)));
Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits<qint16>::max());
VectorXint16 samples_int = samples_int_tmp.cast<qint16>();
QByteArray raw = QByteArray(reinterpret_cast<char*>(samples_int.data()), int(samples_int.size()) * int(sizeof(qint16)));
return raw;
}
default:
break;
}
break;
}
case 32:
{
switch (supported_format.sampleType())
{
case QAudioFormat::SignedInt:
{
Eigen::Ref<Eigen::VectorXf> samples_float = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(input.data()), input.size() / int(sizeof(float)));
Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits<qint32>::max());
VectorXint32 samples_int = samples_int_tmp.cast<qint32>();
QByteArray raw = QByteArray(reinterpret_cast<char*>(samples_int.data()), int(samples_int.size()) * int(sizeof(qint32)));
return raw;
}
default:
break;
}
break;
}
default:
break;
}
return QByteArray();
}
static inline QByteArray samplesToFloat(const QByteArray& data, const QAudioFormat& supported_format)
{
QByteArray input = data;
switch (supported_format.sampleSize())
{
case 8:
{
switch (supported_format.sampleType())
{
case QAudioFormat::UnSignedInt:
{
QByteArray raw = input;
Eigen::Ref<VectorXuint8> samples_int = Eigen::Map<VectorXuint8>(reinterpret_cast<quint8*>(raw.data()), raw.size() / int(sizeof(quint8)));
Eigen::VectorXf samples_float = samples_int.cast<float>() / float(std::numeric_limits<quint8>::max());
return QByteArray(reinterpret_cast<char*>(samples_float.data()), int(samples_float.size()) * int(sizeof(float)));
}
case QAudioFormat::SignedInt:
{
QByteArray raw = input;
Eigen::Ref<VectorXint8> samples_int = Eigen::Map<VectorXint8>(reinterpret_cast<qint8*>(raw.data()), raw.size() / int(sizeof(qint8)));
Eigen::VectorXf samples_float = samples_int.cast<float>() / float(std::numeric_limits<qint8>::max());
return QByteArray(reinterpret_cast<char*>(samples_float.data()), int(samples_float.size()) * int(sizeof(float)));
}
default:
break;
}
break;
}
case 16:
{
switch (supported_format.sampleType())
{
case QAudioFormat::SignedInt:
{
QByteArray raw = input;
Eigen::Ref<VectorXint16> samples_int = Eigen::Map<VectorXint16>(reinterpret_cast<qint16*>(raw.data()), raw.size() / int(sizeof(qint16)));
Eigen::VectorXf samples_float = samples_int.cast<float>() / float(std::numeric_limits<qint16>::max());
return QByteArray(reinterpret_cast<char*>(samples_float.data()), int(samples_float.size()) * int(sizeof(float)));
}
default:
break;
}
break;
}
case 32:
{
switch (supported_format.sampleType())
{
case QAudioFormat::SignedInt:
{
QByteArray raw = input;
Eigen::Ref<VectorXint32> samples_int = Eigen::Map<VectorXint32>(reinterpret_cast<qint32*>(raw.data()), raw.size() / int(sizeof(qint32)));
Eigen::VectorXf samples_float = samples_int.cast<float>() / float(std::numeric_limits<qint32>::max());
return QByteArray(reinterpret_cast<char*>(samples_float.data()), int(samples_float.size()) * int(sizeof(float)));
}
default:
break;
}
break;
}
default:
break;
}
return QByteArray();
}
#endif // AUDIOHANDLER_H

Wyświetl plik

@ -151,7 +151,7 @@ void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, aud
connect(ptty, SIGNAL(haveDataFromPort(QByteArray)), udp, SLOT(receiveDataFromUserToRig(QByteArray)));
// data from the tcp port to the Rig:
connect(tcp, SIGNAL(haveData(QByteArray)), udp, SLOT(receiveDataFromUserToRig(QByteArray)));
connect(tcp, SIGNAL(receiveData(QByteArray)), udp, SLOT(receiveDataFromUserToRig(QByteArray)));
connect(this, SIGNAL(haveChangeLatency(quint16)), udp, SLOT(changeLatency(quint16)));
connect(this, SIGNAL(haveSetVolume(unsigned char)), udp, SLOT(setVolume(unsigned char)));

Wyświetl plik

@ -28,6 +28,7 @@ int tcpServer::startServer(qint16 port) {
void tcpServer::incomingConnection(qintptr socket) {
tcpServerClient* client = new tcpServerClient(socket, this);
connect(this, SIGNAL(onStopped()), client, SLOT(closeSocket()));
emit newClient(socket); // Signal par
}
void tcpServer::stopServer()
@ -39,7 +40,7 @@ void tcpServer::stopServer()
void tcpServer::receiveDataFromClient(QByteArray data)
{
emit haveData(data);
emit receiveData(data);
}
void tcpServer::sendData(QByteArray data) {

Wyświetl plik

@ -29,8 +29,9 @@ public slots:
signals:
void onStarted();
void onStopped();
void haveData(QByteArray data); // emit this when we have data from tcp client, connect to rigcommander
void receiveData(QByteArray data); // emit this when we have data from tcp client, connect to rigcommander
void sendDataToClient(QByteArray data);
void newClient(int socketId);
private:
QTcpServer* server;

Wyświetl plik

@ -20,8 +20,8 @@ udpHandler::udpHandler(udpPreferences prefs, audioSetup rx, audioSetup tx) :
this->password = prefs.password;
this->compName = prefs.clientName.mid(0,8) + "-wfview";
qInfo(logUdp()) << "Starting udpHandler user:" << username << " rx latency:" << rxSetup.latency << " tx latency:" << txSetup.latency << " rx sample rate: " << rxSetup.samplerate <<
" rx codec: " << rxSetup.codec << " tx sample rate: " << txSetup.samplerate << " tx codec: " << txSetup.codec;
qInfo(logUdp()) << "Starting udpHandler user:" << username << " rx latency:" << rxSetup.latency << " tx latency:" << txSetup.latency << " rx sample rate: " << rxSetup.format.sampleRate() <<
" rx codec: " << rxSetup.codec << " tx sample rate: " << txSetup.format.sampleRate() << " tx codec: " << txSetup.codec;
// Try to set the IP address, if it is a hostname then perform a DNS lookup.
if (!radioIP.setAddress(prefs.ipAddress))
@ -280,7 +280,7 @@ void udpHandler::dataReceived()
// TX is not supported
if (txSampleRates < 2) {
txSetup.samplerate = 0;
txSetup.format.setSampleRate(0);
txSetup.codec = 0;
}
audio = new udpAudio(localIP, radioIP, audioPort, audioLocalPort, rxSetup, txSetup);
@ -512,8 +512,8 @@ void udpHandler::sendRequestStream()
}
p.rxcodec = rxSetup.codec;
memcpy(&p.username, usernameEncoded.constData(), usernameEncoded.length());
p.rxsample = qToBigEndian((quint32)rxSetup.samplerate);
p.txsample = qToBigEndian((quint32)txSetup.samplerate);
p.rxsample = qToBigEndian((quint32)rxSetup.format.sampleRate());
p.txsample = qToBigEndian((quint32)txSetup.format.sampleRate());
p.civport = qToBigEndian((quint32)civLocalPort);
p.audioport = qToBigEndian((quint32)audioLocalPort);
p.txbuffer = qToBigEndian((quint32)txSetup.latency);
@ -789,7 +789,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
this->port = audioPort;
this->radioIP = ip;
if (txSetup.samplerate == 0) {
if (txSetup.format.sampleRate() == 0) {
enableTx = false;
}
@ -812,7 +812,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
connect(this, SIGNAL(haveSetVolume(unsigned char)), rxaudio, SLOT(setVolume(unsigned char)));
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
txSetup.radioChan = 1;
txSetup.format.setChannelCount(1); // TX Audio is always single channel.
txaudio = new audioHandler();
txAudioThread = new QThread(this);

Wyświetl plik

@ -350,7 +350,7 @@ void udpServer::controlReceived()
if (!memcmp(radio->guid, current->guid, GUIDLEN) && radio->txaudio == Q_NULLPTR)
{
radio->txAudioSetup.codec = current->txCodec;
radio->txAudioSetup.samplerate = current->txSampleRate;
radio->txAudioSetup.format.setSampleRate(current->txSampleRate);
radio->txAudioSetup.isinput = false;
radio->txAudioSetup.latency = current->txBufferLen;
outAudio.isinput = false;
@ -390,7 +390,7 @@ void udpServer::controlReceived()
#endif
radio->rxAudioSetup.codec = current->rxCodec;
radio->rxAudioSetup.samplerate = current->rxSampleRate;
radio->rxAudioSetup.format.setSampleRate(current->rxSampleRate);
radio->rxAudioSetup.latency = current->txBufferLen;
radio->rxAudioSetup.isinput = true;

Wyświetl plik

@ -1552,10 +1552,11 @@ void wfmain::loadSettings()
ui->txLatencySlider->setTracking(false); // Stop it sending value on every change.
ui->audioSampleRateCombo->blockSignals(true);
rxSetup.samplerate = settings->value("AudioRXSampleRate", "48000").toInt();
txSetup.samplerate = rxSetup.samplerate;
rxSetup.format.setSampleRate(settings->value("AudioRXSampleRate", "48000").toInt());
txSetup.format.setSampleRate(rxSetup.format.sampleRate());
ui->audioSampleRateCombo->setEnabled(ui->lanEnableBtn->isChecked());
int audioSampleRateIndex = ui->audioSampleRateCombo->findText(QString::number(rxSetup.samplerate));
int audioSampleRateIndex = ui->audioSampleRateCombo->findText(QString::number(rxSetup.format.sampleRate()));
if (audioSampleRateIndex != -1) {
ui->audioSampleRateCombo->setCurrentIndex(audioSampleRateIndex);
}
@ -1974,9 +1975,9 @@ void wfmain::saveSettings()
settings->setValue("Password", udpPrefs.password);
settings->setValue("AudioRXLatency", rxSetup.latency);
settings->setValue("AudioTXLatency", txSetup.latency);
settings->setValue("AudioRXSampleRate", rxSetup.samplerate);
settings->setValue("AudioRXSampleRate", rxSetup.format.sampleRate());
settings->setValue("AudioRXCodec", rxSetup.codec);
settings->setValue("AudioTXSampleRate", txSetup.samplerate);
settings->setValue("AudioTXSampleRate", txSetup.format.sampleRate());
settings->setValue("AudioTXCodec", txSetup.codec);
settings->setValue("AudioOutput", rxSetup.name);
settings->setValue("AudioInput", txSetup.name);
@ -4721,8 +4722,8 @@ void wfmain::on_audioSampleRateCombo_currentIndexChanged(QString text)
{
//udpPrefs.audioRXSampleRate = text.toInt();
//udpPrefs.audioTXSampleRate = text.toInt();
rxSetup.samplerate = text.toInt();
txSetup.samplerate = text.toInt();
rxSetup.format.setSampleRate(text.toInt());
txSetup.format.setSampleRate(text.toInt());
}
void wfmain::on_audioRXCodecCombo_currentIndexChanged(int value)

Wyświetl plik

@ -150,7 +150,8 @@ macx:LIBS += -framework CoreAudio -framework CoreFoundation -lpthread -lopus
!linux:INCLUDEPATH += ../opus/include
!linux:INCLUDEPATH += ../eigen/Eigen
!linux:INCLUDEPATH += ../eigen
!linux:INCLUDEPATH += ../r8brain-free-src
INCLUDEPATH += resampler
@ -175,8 +176,8 @@ SOURCES += main.cpp\
ring/ring.cpp \
transceiveradjustments.cpp \
selectradio.cpp \
tcpserver.cpp \
aboutbox.cpp
tcpserver.cpp \
aboutbox.cpp
HEADERS += wfmain.h \
commhandler.h \
@ -204,7 +205,8 @@ HEADERS += wfmain.h \
transceiveradjustments.h \
audiotaper.h \
selectradio.h \
tcpserver.h \
tcpserver.h \
audiocommon.h \
aboutbox.h

Wyświetl plik

@ -48,7 +48,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>.;..\qcustomplot;..\opus\include;..\eigen\Eigen;resampler;release;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;release;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
<AssemblerListingLocation>release\</AssemblerListingLocation>
<BrowseInformation>false</BrowseInformation>
@ -57,7 +57,7 @@
<ExceptionHandling>Sync</ExceptionHandling>
<ObjectFileName>release\</ObjectFileName>
<Optimization>MaxSpeed</Optimization>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.2d";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="c5cf0fd";HOST="wfview.org";UNAME="build";NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.2d";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="8ec62fe";HOST="wfview.org";UNAME="build";NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile>
<ProgramDataBaseFileName></ProgramDataBaseFileName>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@ -85,12 +85,12 @@
<WarningLevel>0</WarningLevel>
</Midl>
<ResourceCompile>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2d\";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=\"c5cf0fd\";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>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2d\";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=\"8ec62fe\";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>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>.;..\qcustomplot;..\opus\include;..\eigen\Eigen;resampler;debug;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;debug;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
<AssemblerListingLocation>debug\</AssemblerListingLocation>
<BrowseInformation>false</BrowseInformation>
@ -99,7 +99,7 @@
<ExceptionHandling>Sync</ExceptionHandling>
<ObjectFileName>debug\</ObjectFileName>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.2d";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="c5cf0fd";HOST="wfview.org";UNAME="build";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.2d";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="8ec62fe";HOST="wfview.org";UNAME="build";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<SuppressStartupBanner>true</SuppressStartupBanner>
@ -124,7 +124,7 @@
<WarningLevel>0</WarningLevel>
</Midl>
<ResourceCompile>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2d\";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=\"c5cf0fd\";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>
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2d\";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=\"8ec62fe\";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>
<ItemGroup>
@ -165,6 +165,7 @@
</QtMoc>
<ClInclude Include="resampler\arch.h" />
<ClInclude Include="audiocommon.h" />
<QtMoc Include="audiohandler.h">

Wyświetl plik

@ -127,6 +127,9 @@
<ClInclude Include="resampler\arch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="audiocommon.h">
<Filter>Header Files</Filter>
</ClInclude>
<QtMoc Include="audiohandler.h">
<Filter>Header Files</Filter>
</QtMoc>