Audio metering initial. Very messy but you can select TxRxAudio as the

meter type and wfview will show you TX or RX audio depending upon if you
are transmitting or not. You can also select only TxAudio or RxAudio.
This is nice for looking at Tx audio levels prior to transmitting, for
example, or metering the radio's "monitor" audio while transmitting.
monitor
Elliott Liggett 2022-08-23 22:24:05 -07:00
rodzic 105675a128
commit 9fb74ed6e1
13 zmienionych plików z 123 dodań i 12 usunięć

Wyświetl plik

@ -157,7 +157,9 @@ bool audioConverter::convert(audioPacket audio)
if (samplesF.size() > 0) if (samplesF.size() > 0)
{ {
audio.amplitude = samplesF.array().abs().maxCoeff(); audio.amplitudePeak = samplesF.array().abs().maxCoeff();
audio.amplitudeRMS = samplesF.squaredNorm();
// Set the volume // Set the volume
samplesF *= audio.volume; samplesF *= audio.volume;

Wyświetl plik

@ -29,7 +29,8 @@ struct audioPacket {
quint16 sent; quint16 sent;
QByteArray data; QByteArray data;
quint8 guid[GUIDLEN]; quint8 guid[GUIDLEN];
float amplitude; float amplitudePeak;
float amplitudeRMS;
qreal volume = 1.0; qreal volume = 1.0;
}; };

Wyświetl plik

@ -270,12 +270,18 @@ void audioHandler::convertedOutput(audioPacket packet) {
} }
*/ */
lastSentSeq = packet.seq; lastSentSeq = packet.seq;
amplitude = packet.amplitudePeak;
computeLevels();
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun);
amplitude = packet.amplitude;
} }
} }
void audioHandler::computeLevels()
{
if(levelMean)
levelMean[(levelPosition++)%levelSize] = amplitude * 255;
}
void audioHandler::getNextAudioChunk() void audioHandler::getNextAudioChunk()
{ {
if (audioDevice) { 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 ; qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize ;
} }
lastReceived = QTime::currentTime(); lastReceived = QTime::currentTime();
amplitude = audio.amplitude; amplitude = audio.amplitudePeak;
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun);
} }
} }

Wyświetl plik

@ -116,6 +116,12 @@ private:
float amplitude=0.0; float amplitude=0.0;
qreal volume = 1.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; audioSetup setup;
OpusEncoder* encoder = Q_NULLPTR; OpusEncoder* encoder = Q_NULLPTR;

Wyświetl plik

@ -278,7 +278,7 @@ void paHandler::convertedOutput(audioPacket packet) {
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->outputLatency * 1000); currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->outputLatency * 1000);
} }
amplitude = packet.amplitude; amplitude = packet.amplitudePeak;
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun);
} }
} }
@ -289,7 +289,7 @@ void paHandler::convertedInput(audioPacket packet)
{ {
if (packet.data.size() > 0) { if (packet.data.size() > 0) {
emit haveAudioData(packet); emit haveAudioData(packet);
amplitude = packet.amplitude; amplitude = packet.amplitudePeak;
const PaStreamInfo* info = Pa_GetStreamInfo(audio); const PaStreamInfo* info = Pa_GetStreamInfo(audio);
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->inputLatency * 1000); currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->inputLatency * 1000);
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun);

Wyświetl plik

@ -166,6 +166,8 @@ void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, aud
// Connect for errors/alerts // Connect for errors/alerts
connect(udp, SIGNAL(haveNetworkError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); connect(udp, SIGNAL(haveNetworkError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString)));
connect(udp, SIGNAL(haveNetworkStatus(networkStatus)), this, SLOT(handleStatusUpdate(networkStatus))); 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(ptty, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString)));
connect(this, SIGNAL(getMoreDebug()), ptty, SLOT(debugThis())); connect(this, SIGNAL(getMoreDebug()), ptty, SLOT(debugThis()));
@ -245,6 +247,11 @@ void rigCommander::handleStatusUpdate(const networkStatus status)
emit haveStatusUpdate(status); emit haveStatusUpdate(status);
} }
void rigCommander::handleNetworkAudioLevels(networkAudioLevels l)
{
emit haveNetworkAudioLevels(l);
}
bool rigCommander::usingLAN() bool rigCommander::usingLAN()
{ {
return usingNativeLAN; return usingNativeLAN;

Wyświetl plik

@ -36,6 +36,7 @@ enum meterKind {
meterRxdB, meterRxdB,
meterTxMod, meterTxMod,
meterRxAudio, meterRxAudio,
meterAudio,
meterLatency meterLatency
}; };
@ -277,6 +278,7 @@ public slots:
// Housekeeping: // Housekeeping:
void handleStatusUpdate(const networkStatus status); void handleStatusUpdate(const networkStatus status);
void handleNetworkAudioLevels(networkAudioLevels);
void radioSelection(QList<radio_cap_packet> radios); void radioSelection(QList<radio_cap_packet> radios);
void radioUsage(quint8 radio, quint8 busy, QString name, QString ip); void radioUsage(quint8 radio, quint8 busy, QString name, QString ip);
void setCurrentRadio(quint8 radio); void setCurrentRadio(quint8 radio);
@ -288,6 +290,7 @@ signals:
void commReady(); void commReady();
void haveSerialPortError(const QString port, const QString errorText); void haveSerialPortError(const QString port, const QString errorText);
void haveStatusUpdate(const networkStatus status); void haveStatusUpdate(const networkStatus status);
void haveNetworkAudioLevels(const networkAudioLevels l);
void dataForComm(const QByteArray &outData); void dataForComm(const QByteArray &outData);
void toggleRTS(bool rtsOn); void toggleRTS(bool rtsOn);
@ -397,6 +400,11 @@ private:
quint16 decodeTone(QByteArray eTone); quint16 decodeTone(QByteArray eTone);
quint16 decodeTone(QByteArray eTone, bool &tinv, bool &rinv); 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 parseMode();
void parseSpectrum(); void parseSpectrum();
void parseWFData(); void parseWFData();

Wyświetl plik

@ -331,7 +331,7 @@ void rtHandler::convertedOutput(audioPacket packet)
audioMutex.lock(); audioMutex.lock();
arrayBuffer.append(packet.data); arrayBuffer.append(packet.data);
audioMutex.unlock(); audioMutex.unlock();
amplitude = packet.amplitude; amplitude = packet.amplitudePeak;
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audio->getStreamLatency() * (outFormat.sampleSize() / 8) * outFormat.channelCount())/1000); currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audio->getStreamLatency() * (outFormat.sampleSize() / 8) * outFormat.channelCount())/1000);
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun);
} }
@ -342,7 +342,7 @@ void rtHandler::convertedInput(audioPacket packet)
{ {
if (packet.data.size() > 0) { if (packet.data.size() > 0) {
emit haveAudioData(packet); 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); currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audio->getStreamLatency() * (outFormat.sampleSize() / 8) * outFormat.channelCount())/1000);
emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun); emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun, isOverrun);
} }

Wyświetl plik

@ -37,6 +37,15 @@ struct udpPreferences {
quint8 waterfallFormat; quint8 waterfallFormat;
}; };
struct networkAudioLevels {
bool haveTxLevels = false;
bool haveRxLevels = false;
quint8 rxAudioRMS = 0;
quint8 txAudioRMS = 0;
quint8 rxAudioPeak = 0;
quint8 txAudioPeak = 0;
};
struct networkStatus { struct networkStatus {
quint8 rxAudioBufferPercent; quint8 rxAudioBufferPercent;
quint8 txAudioBufferPercent; quint8 txAudioBufferPercent;

Wyświetl plik

@ -149,6 +149,17 @@ void udpHandler::getRxLevels(quint16 amplitude,quint16 latency,quint16 current,
status.rxCurrentLatency = current; status.rxCurrentLatency = current;
status.rxUnderrun = under; status.rxUnderrun = under;
status.rxOverrun = over; 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) { 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.txCurrentLatency = current;
status.txUnderrun = under; status.txUnderrun = under;
status.txOverrun = over; 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() void udpHandler::dataReceived()

Wyświetl plik

@ -29,7 +29,7 @@
#include "udpcivdata.h" #include "udpcivdata.h"
#include "udpaudio.h" #include "udpaudio.h"
#define audioLevelBufferSize (3)
// Class to handle the connection/disconnection of the radio. // Class to handle the connection/disconnection of the radio.
class udpHandler: public udpBase class udpHandler: public udpBase
@ -58,7 +58,8 @@ public slots:
void setCurrentRadio(quint8 radio); void setCurrentRadio(quint8 radio);
void getRxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under, bool over); 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 getTxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under, bool over);
//void handleRxLevels(networkAudioLevels);
//void handleTxLevels(networkAudioLevels);
signals: signals:
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
@ -67,6 +68,7 @@ signals:
void haveChangeLatency(quint16 value); void haveChangeLatency(quint16 value);
void haveSetVolume(unsigned char value); void haveSetVolume(unsigned char value);
void haveNetworkStatus(networkStatus); void haveNetworkStatus(networkStatus);
void haveNetworkAudioLevels(networkAudioLevels);
void haveBaudRate(quint32 baudrate); void haveBaudRate(quint32 baudrate);
void requestRadioSelection(QList<radio_cap_packet> radios); void requestRadioSelection(QList<radio_cap_packet> radios);
void setRadioUsage(quint8, quint8 busy, QString name, QString mac); void setRadioUsage(quint8, quint8 busy, QString name, QString mac);
@ -122,6 +124,14 @@ private:
quint16 txSampleRates = 0; quint16 txSampleRates = 0;
networkStatus status; networkStatus status;
bool splitWf = false; 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);
}; };

Wyświetl plik

@ -47,6 +47,7 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s
qRegisterMetaType<rigstate*>(); qRegisterMetaType<rigstate*>();
qRegisterMetaType<QList<radio_cap_packet>>(); qRegisterMetaType<QList<radio_cap_packet>>();
qRegisterMetaType<networkStatus>(); qRegisterMetaType<networkStatus>();
qRegisterMetaType<networkAudioLevels>();
haveRigCaps = false; haveRigCaps = false;
@ -424,6 +425,7 @@ void wfmain::makeRig()
// Rig status and Errors: // Rig status and Errors:
connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString)));
connect(rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus))); connect(rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus)));
connect(rig, SIGNAL(haveNetworkAudioLevels(networkAudioLevels)), this, SLOT(receiveNetworkAudioLevels(networkAudioLevels)));
connect(rig, SIGNAL(requestRadioSelection(QList<radio_cap_packet>)), this, SLOT(radioSelection(QList<radio_cap_packet>))); connect(rig, SIGNAL(requestRadioSelection(QList<radio_cap_packet>)), this, SLOT(radioSelection(QList<radio_cap_packet>)));
connect(rig, SIGNAL(setRadioUsage(quint8, quint8, QString, QString)), selRad, SLOT(setInUse(quint8, quint8, QString, QString))); connect(rig, SIGNAL(setRadioUsage(quint8, quint8, QString, QString)), selRad, SLOT(setInUse(quint8, quint8, QString, QString)));
connect(selRad, SIGNAL(selectedRadio(quint8)), rig, SLOT(setCurrentRadio(quint8))); 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; //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() void wfmain::setupPlots()
{ {
spectrumDrawLock = true; spectrumDrawLock = true;
@ -746,6 +764,10 @@ void wfmain::setupMainUI()
ui->meter2selectionCombo->addItem("Voltage", meterVoltage); ui->meter2selectionCombo->addItem("Voltage", meterVoltage);
ui->meter2selectionCombo->addItem("Current", meterCurrent); ui->meter2selectionCombo->addItem("Current", meterCurrent);
ui->meter2selectionCombo->addItem("Center", meterCenter); ui->meter2selectionCombo->addItem("Center", meterCenter);
ui->meter2selectionCombo->addItem("TxRxAudio", meterAudio);
ui->meter2selectionCombo->addItem("RxAudio", meterRxAudio);
ui->meter2selectionCombo->addItem("TxAudio", meterTxMod);
ui->meter2Widget->hide(); ui->meter2Widget->hide();
ui->meter2selectionCombo->show(); ui->meter2selectionCombo->show();
@ -5096,6 +5118,12 @@ void wfmain::receiveMeter(meterKind inMeter, unsigned char level)
if(ui->meter2Widget->getMeterType() == inMeter) if(ui->meter2Widget->getMeterType() == inMeter)
{ {
ui->meter2Widget->setLevel(level); 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; break;
} }
@ -5765,7 +5793,8 @@ void wfmain::on_meter2selectionCombo_activated(int index)
} else { } else {
ui->meter2Widget->show(); ui->meter2Widget->show();
ui->meter2Widget->setMeterType(newMeterType); ui->meter2Widget->setMeterType(newMeterType);
insertPeriodicCommandUnique(newCmd); if((newMeterType!=meterRxAudio) && (newMeterType!=meterTxMod) && (newMeterType!=meterAudio))
insertPeriodicCommandUnique(newCmd);
} }
prefs.meter2Type = newMeterType; prefs.meter2Type = newMeterType;

Wyświetl plik

@ -275,6 +275,7 @@ private slots:
void receiveFoundRigID(rigCapabilities rigCaps); void receiveFoundRigID(rigCapabilities rigCaps);
void receiveSerialPortError(QString port, QString errorText); void receiveSerialPortError(QString port, QString errorText);
void receiveStatusUpdate(networkStatus status); void receiveStatusUpdate(networkStatus status);
void receiveNetworkAudioLevels(networkAudioLevels l);
void handlePlotClick(QMouseEvent *); void handlePlotClick(QMouseEvent *);
void handlePlotDoubleClick(QMouseEvent *); void handlePlotDoubleClick(QMouseEvent *);
void handleWFClick(QMouseEvent *); void handleWFClick(QMouseEvent *);
@ -943,6 +944,7 @@ Q_DECLARE_METATYPE(struct SERVERCONFIG)
Q_DECLARE_METATYPE(struct timekind) Q_DECLARE_METATYPE(struct timekind)
Q_DECLARE_METATYPE(struct datekind) Q_DECLARE_METATYPE(struct datekind)
Q_DECLARE_METATYPE(struct networkStatus) Q_DECLARE_METATYPE(struct networkStatus)
Q_DECLARE_METATYPE(struct networkAudioLevels)
Q_DECLARE_METATYPE(enum rigInput) Q_DECLARE_METATYPE(enum rigInput)
Q_DECLARE_METATYPE(enum meterKind) Q_DECLARE_METATYPE(enum meterKind)
Q_DECLARE_METATYPE(enum spectrumMode) Q_DECLARE_METATYPE(enum spectrumMode)