diff --git a/audioconverter.cpp b/audioconverter.cpp index 2316229..d97da05 100644 --- a/audioconverter.cpp +++ b/audioconverter.cpp @@ -157,7 +157,9 @@ bool audioConverter::convert(audioPacket audio) if (samplesF.size() > 0) { - audio.amplitude = samplesF.array().abs().maxCoeff(); + audio.amplitudePeak = samplesF.array().abs().maxCoeff(); + audio.amplitudeRMS = samplesF.squaredNorm(); + // Set the volume samplesF *= audio.volume; diff --git a/audioconverter.h b/audioconverter.h index a0d2953..b3a1492 100644 --- a/audioconverter.h +++ b/audioconverter.h @@ -29,7 +29,8 @@ struct audioPacket { quint16 sent; QByteArray data; quint8 guid[GUIDLEN]; - float amplitude; + float amplitudePeak; + float amplitudeRMS; qreal volume = 1.0; }; diff --git a/audiohandler.cpp b/audiohandler.cpp index cf49045..6968410 100644 --- a/audiohandler.cpp +++ b/audiohandler.cpp @@ -270,12 +270,18 @@ void audioHandler::convertedOutput(audioPacket packet) { } */ lastSentSeq = packet.seq; + amplitude = packet.amplitudePeak; + computeLevels(); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); - - amplitude = packet.amplitude; } } +void audioHandler::computeLevels() +{ + if(levelMean) + levelMean[(levelPosition++)%levelSize] = amplitude * 255; +} + void audioHandler::getNextAudioChunk() { if (audioDevice) { @@ -312,7 +318,7 @@ void audioHandler::convertedInput(audioPacket audio) qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize ; } lastReceived = QTime::currentTime(); - amplitude = audio.amplitude; + amplitude = audio.amplitudePeak; emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); } } diff --git a/audiohandler.h b/audiohandler.h index a793973..7c8412b 100644 --- a/audiohandler.h +++ b/audiohandler.h @@ -116,6 +116,12 @@ private: float amplitude=0.0; qreal volume = 1.0; + unsigned char *levelMean = Q_NULLPTR; + unsigned char *levelPeak = Q_NULLPTR; + unsigned char levelSize = 50; + unsigned char levelPosition = 0; + void computeLevels(); + audioSetup setup; OpusEncoder* encoder = Q_NULLPTR; diff --git a/pahandler.cpp b/pahandler.cpp index 9db91d1..f437e0c 100644 --- a/pahandler.cpp +++ b/pahandler.cpp @@ -278,7 +278,7 @@ void paHandler::convertedOutput(audioPacket packet) { currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->outputLatency * 1000); } - amplitude = packet.amplitude; + amplitude = packet.amplitudePeak; emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); } } @@ -289,7 +289,7 @@ void paHandler::convertedInput(audioPacket packet) { if (packet.data.size() > 0) { emit haveAudioData(packet); - amplitude = packet.amplitude; + amplitude = packet.amplitudePeak; const PaStreamInfo* info = Pa_GetStreamInfo(audio); currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->inputLatency * 1000); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); diff --git a/rigcommander.cpp b/rigcommander.cpp index c0d3ea6..d6ea80c 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -166,6 +166,8 @@ void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, aud // Connect for errors/alerts connect(udp, SIGNAL(haveNetworkError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); connect(udp, SIGNAL(haveNetworkStatus(networkStatus)), this, SLOT(handleStatusUpdate(networkStatus))); + connect(udp, SIGNAL(haveNetworkAudioLevels(networkAudioLevels)), this, SLOT(handleNetworkAudioLevels(networkAudioLevels))); + connect(ptty, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); connect(this, SIGNAL(getMoreDebug()), ptty, SLOT(debugThis())); @@ -245,6 +247,11 @@ void rigCommander::handleStatusUpdate(const networkStatus status) emit haveStatusUpdate(status); } +void rigCommander::handleNetworkAudioLevels(networkAudioLevels l) +{ + emit haveNetworkAudioLevels(l); +} + bool rigCommander::usingLAN() { return usingNativeLAN; diff --git a/rigcommander.h b/rigcommander.h index 7921b24..e26941e 100644 --- a/rigcommander.h +++ b/rigcommander.h @@ -36,6 +36,7 @@ enum meterKind { meterRxdB, meterTxMod, meterRxAudio, + meterAudio, meterLatency }; @@ -277,6 +278,7 @@ public slots: // Housekeeping: void handleStatusUpdate(const networkStatus status); + void handleNetworkAudioLevels(networkAudioLevels); void radioSelection(QList radios); void radioUsage(quint8 radio, quint8 busy, QString name, QString ip); void setCurrentRadio(quint8 radio); @@ -288,6 +290,7 @@ signals: void commReady(); void haveSerialPortError(const QString port, const QString errorText); void haveStatusUpdate(const networkStatus status); + void haveNetworkAudioLevels(const networkAudioLevels l); void dataForComm(const QByteArray &outData); void toggleRTS(bool rtsOn); @@ -397,6 +400,11 @@ private: quint16 decodeTone(QByteArray eTone); quint16 decodeTone(QByteArray eTone, bool &tinv, bool &rinv); + unsigned char audioLevelRxMean[50]; + unsigned char audioLevelRxPeak[50]; + unsigned char audioLevelTxMean[50]; + unsigned char audioLevelTxPeak[50]; + void parseMode(); void parseSpectrum(); void parseWFData(); diff --git a/rthandler.cpp b/rthandler.cpp index f848c38..73b8edb 100644 --- a/rthandler.cpp +++ b/rthandler.cpp @@ -331,7 +331,7 @@ void rtHandler::convertedOutput(audioPacket packet) audioMutex.lock(); arrayBuffer.append(packet.data); audioMutex.unlock(); - amplitude = packet.amplitude; + amplitude = packet.amplitudePeak; currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audio->getStreamLatency() * (outFormat.sampleSize() / 8) * outFormat.channelCount())/1000); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); } @@ -342,7 +342,7 @@ void rtHandler::convertedInput(audioPacket packet) { if (packet.data.size() > 0) { emit haveAudioData(packet); - amplitude = packet.amplitude; + amplitude = packet.amplitudePeak; currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audio->getStreamLatency() * (outFormat.sampleSize() / 8) * outFormat.channelCount())/1000); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); } diff --git a/udpbase.h b/udpbase.h index f042b4d..e5c67cf 100644 --- a/udpbase.h +++ b/udpbase.h @@ -37,6 +37,15 @@ struct udpPreferences { quint8 waterfallFormat; }; +struct networkAudioLevels { + bool haveTxLevels = false; + bool haveRxLevels = false; + quint8 rxAudioRMS = 0; + quint8 txAudioRMS = 0; + quint8 rxAudioPeak = 0; + quint8 txAudioPeak = 0; +}; + struct networkStatus { quint8 rxAudioBufferPercent; quint8 txAudioBufferPercent; diff --git a/udphandler.cpp b/udphandler.cpp index f0ffd60..fd32779 100644 --- a/udphandler.cpp +++ b/udphandler.cpp @@ -149,6 +149,17 @@ void udpHandler::getRxLevels(quint16 amplitude,quint16 latency,quint16 current, status.rxCurrentLatency = current; status.rxUnderrun = under; status.rxOverrun = over; + audioLevelsRxPeak[(audioLevelsRxPeakPosition++)%audioLevelBufferSize] = amplitude; + if((audioLevelsRxPeakPosition++)%3 == 0) + { + // calculate mean and emit signal + unsigned char mean = findMean(audioLevelsRxPeak); + networkAudioLevels l; + l.haveRxLevels = true; + l.rxAudioPeak = mean; + //qDebug(logSystem()) << "audio level meter being emitted from udpHandler"; + emit haveNetworkAudioLevels(l); + } } void udpHandler::getTxLevels(quint16 amplitude,quint16 latency, quint16 current, bool under, bool over) { @@ -157,6 +168,26 @@ void udpHandler::getTxLevels(quint16 amplitude,quint16 latency, quint16 current, status.txCurrentLatency = current; status.txUnderrun = under; status.txOverrun = over; + audioLevelsTxPeak[(audioLevelsTxPeakPosition++)%audioLevelBufferSize] = amplitude; + if((audioLevelsTxPeakPosition++)%3 == 0) + { + // calculate mean and emit signal + unsigned char mean = findMean(audioLevelsTxPeak); + networkAudioLevels l; + l.haveTxLevels = true; + l.txAudioPeak = mean; + emit haveNetworkAudioLevels(l); + } +} + +unsigned char udpHandler::findMean(unsigned char *data) +{ + unsigned int sum=0; + for(int p=0; p < audioLevelBufferSize; p++) + { + sum += data[p]; + } + return sum / audioLevelBufferSize; } void udpHandler::dataReceived() diff --git a/udphandler.h b/udphandler.h index 8300805..231577c 100644 --- a/udphandler.h +++ b/udphandler.h @@ -29,7 +29,7 @@ #include "udpcivdata.h" #include "udpaudio.h" - +#define audioLevelBufferSize (3) // Class to handle the connection/disconnection of the radio. class udpHandler: public udpBase @@ -58,7 +58,8 @@ public slots: void setCurrentRadio(quint8 radio); void getRxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under, bool over); void getTxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under, bool over); - + //void handleRxLevels(networkAudioLevels); + //void handleTxLevels(networkAudioLevels); signals: void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander @@ -67,6 +68,7 @@ signals: void haveChangeLatency(quint16 value); void haveSetVolume(unsigned char value); void haveNetworkStatus(networkStatus); + void haveNetworkAudioLevels(networkAudioLevels); void haveBaudRate(quint32 baudrate); void requestRadioSelection(QList radios); void setRadioUsage(quint8, quint8 busy, QString name, QString mac); @@ -122,6 +124,14 @@ private: quint16 txSampleRates = 0; networkStatus status; bool splitWf = false; + + unsigned char audioLevelsTxPeak[audioLevelBufferSize]; + unsigned char audioLevelsRxPeak[audioLevelBufferSize]; + unsigned char audioLevelsTxPeakPosition = 0; + unsigned char audioLevelsRxPeakPosition = 0; + unsigned char findMean(unsigned char *d); + + }; diff --git a/wfmain.cpp b/wfmain.cpp index c55d6cc..6ed376b 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -47,6 +47,7 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s qRegisterMetaType(); qRegisterMetaType>(); qRegisterMetaType(); + qRegisterMetaType(); haveRigCaps = false; @@ -424,6 +425,7 @@ void wfmain::makeRig() // Rig status and Errors: connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); connect(rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus))); + connect(rig, SIGNAL(haveNetworkAudioLevels(networkAudioLevels)), this, SLOT(receiveNetworkAudioLevels(networkAudioLevels))); connect(rig, SIGNAL(requestRadioSelection(QList)), this, SLOT(radioSelection(QList))); connect(rig, SIGNAL(setRadioUsage(quint8, quint8, QString, QString)), selRad, SLOT(setInUse(quint8, quint8, QString, QString))); connect(selRad, SIGNAL(selectedRadio(quint8)), rig, SLOT(setCurrentRadio(quint8))); @@ -615,6 +617,22 @@ void wfmain::receiveStatusUpdate(networkStatus status) //qInfo(logSystem()) << "Got Status Update" << status.rxAudioLevel; } +void wfmain::receiveNetworkAudioLevels(networkAudioLevels l) +{ + qInfo(logSystem()) << "audio level meter received."; + meterKind m = meterNone; + if(l.haveRxLevels) + { + m = meterRxAudio; + receiveMeter(m, l.rxAudioPeak); + } + if(l.haveTxLevels) + { + m = meterTxMod; + receiveMeter(m, l.txAudioPeak); + } +} + void wfmain::setupPlots() { spectrumDrawLock = true; @@ -746,6 +764,10 @@ void wfmain::setupMainUI() ui->meter2selectionCombo->addItem("Voltage", meterVoltage); ui->meter2selectionCombo->addItem("Current", meterCurrent); ui->meter2selectionCombo->addItem("Center", meterCenter); + ui->meter2selectionCombo->addItem("TxRxAudio", meterAudio); + ui->meter2selectionCombo->addItem("RxAudio", meterRxAudio); + ui->meter2selectionCombo->addItem("TxAudio", meterTxMod); + ui->meter2Widget->hide(); ui->meter2selectionCombo->show(); @@ -5096,6 +5118,12 @@ void wfmain::receiveMeter(meterKind inMeter, unsigned char level) if(ui->meter2Widget->getMeterType() == inMeter) { ui->meter2Widget->setLevel(level); + } else if ( (ui->meter2Widget->getMeterType() == meterAudio) && + (inMeter == meterTxMod) && amTransmitting) { + ui->meter2Widget->setLevel(level); + } else if ( (ui->meter2Widget->getMeterType() == meterAudio) && + (inMeter == meterRxAudio) && !amTransmitting) { + ui->meter2Widget->setLevel(level); } break; } @@ -5765,7 +5793,8 @@ void wfmain::on_meter2selectionCombo_activated(int index) } else { ui->meter2Widget->show(); ui->meter2Widget->setMeterType(newMeterType); - insertPeriodicCommandUnique(newCmd); + if((newMeterType!=meterRxAudio) && (newMeterType!=meterTxMod) && (newMeterType!=meterAudio)) + insertPeriodicCommandUnique(newCmd); } prefs.meter2Type = newMeterType; diff --git a/wfmain.h b/wfmain.h index 55fc8d2..446967a 100644 --- a/wfmain.h +++ b/wfmain.h @@ -275,6 +275,7 @@ private slots: void receiveFoundRigID(rigCapabilities rigCaps); void receiveSerialPortError(QString port, QString errorText); void receiveStatusUpdate(networkStatus status); + void receiveNetworkAudioLevels(networkAudioLevels l); void handlePlotClick(QMouseEvent *); void handlePlotDoubleClick(QMouseEvent *); void handleWFClick(QMouseEvent *); @@ -943,6 +944,7 @@ Q_DECLARE_METATYPE(struct SERVERCONFIG) Q_DECLARE_METATYPE(struct timekind) Q_DECLARE_METATYPE(struct datekind) Q_DECLARE_METATYPE(struct networkStatus) +Q_DECLARE_METATYPE(struct networkAudioLevels) Q_DECLARE_METATYPE(enum rigInput) Q_DECLARE_METATYPE(enum meterKind) Q_DECLARE_METATYPE(enum spectrumMode)