diff --git a/.gitignore b/.gitignore index fd1a2b06..88ca0a41 100644 --- a/.gitignore +++ b/.gitignore @@ -134,6 +134,7 @@ tests/getpids_test tests/log_unlink_test tests/mcast_recv_test tests/metadata_wildcard_test +tests/meterstrip_test tests/notification_test tests/rdxml_parse_test tests/readcd_test diff --git a/ChangeLog b/ChangeLog index c183b460..1c73a86b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21960,3 +21960,5 @@ 2021-06-23 Fred Gleason * Added a voice tracker widget to the right-hand side of rdairplay(1). +2021-06-25 Fred Gleason + * Added an 'RDMeterStrip' widget. diff --git a/lib/Makefile.am b/lib/Makefile.am index 956b764a..5a515d4a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -197,6 +197,7 @@ dist_librd_la_SOURCES = dbversion.h\ rdmatrixlistmodel.cpp rdmatrixlistmodel.h\ rdmblookup.cpp rdmblookup.h\ rdmeteraverage.cpp rdmeteraverage.h\ + rdmeterstrip.cpp rdmeterstrip.h\ rdmixer.cpp rdmixer.h\ rdmonitor_config.cpp rdmonitor_config.h\ rdmp4.cpp rdmp4.h\ @@ -379,6 +380,7 @@ nodist_librd_la_SOURCES = moc_rdadd_cart.cpp\ moc_rdmarkerview.cpp\ moc_rdmatrixlistmodel.cpp\ moc_rdmblookup.cpp\ + moc_rdmeterstrip.cpp\ moc_rdmulticaster.cpp\ moc_rdnodelistmodel.cpp\ moc_rdnodeslotsmodel.cpp\ diff --git a/lib/lib.pro b/lib/lib.pro index e0ecf486..1e214728 100644 --- a/lib/lib.pro +++ b/lib/lib.pro @@ -149,6 +149,7 @@ SOURCES += rdmarkerview.cpp SOURCES += rdmatrix.cpp SOURCES += rdmatrixlistmodel.cpp SOURCES += rdmblookup.cpp +SOURCES += rdmeterstrip.cpp SOURCES += rdmonitor_config.cpp SOURCES += rdnodelistmodel.cpp SOURCES += rdnodeslotsmodel.cpp @@ -334,6 +335,7 @@ HEADERS += rdmarkerview.h HEADERS += rdmatrix.h HEADERS += rdmatrixlistmodel.h HEADERS += rdmblookup.h +HEADERS += rdmeterstrip.h HEADERS += rdmonitor_config.h HEADERS += rdnodelistmodel.h HEADERS += rdnodeslotsmodel.h diff --git a/lib/rdmeterstrip.cpp b/lib/rdmeterstrip.cpp new file mode 100644 index 00000000..ae00c54b --- /dev/null +++ b/lib/rdmeterstrip.cpp @@ -0,0 +1,158 @@ +// rdmeterstrip.cpp +// +// A strip of side-by-side vertical audio meters. +// +// (C) Copyright 2002-2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include "rdmeterstrip.h" + +RDMeterStrip::RDMeterStrip(QWidget *parent) + : RDWidget(parent) +{ + d_poll_timer=new QTimer(this); + connect(d_poll_timer,SIGNAL(timeout()),this,SLOT(pollData())); + d_poll_timer->start(RD_METER_UPDATE_INTERVAL); +} + + +QSize RDMeterStrip::sizeHint() const +{ + return QSize(40*d_types.size(),130); +} + + +QSizePolicy RDMeterStrip::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Minimum,QSizePolicy::MinimumExpanding); +} + + +void RDMeterStrip::addInputMeter(int cardnum,int portnum,const QString &label) +{ + d_types.push_back(RDMeterStrip::Input); + d_card_numbers.push_back(cardnum); + d_port_numbers.push_back(portnum); + + AddMeter(cardnum,portnum,label); +} + + +void RDMeterStrip::addOutputMeter(int cardnum,int portnum,const QString &label) +{ + d_types.push_back(RDMeterStrip::Output); + d_card_numbers.push_back(cardnum); + d_port_numbers.push_back(portnum); + + AddMeter(cardnum,portnum,label); +} + + +void RDMeterStrip::pollData() +{ + short lvls[2]; + + for(int i=0;icae()-> + inputMeterUpdate(d_card_numbers.at(i),d_port_numbers.at(i),lvls); + break; + + case RDMeterStrip::Output: + rda->cae()-> + outputMeterUpdate(d_card_numbers.at(i),d_port_numbers.at(i),lvls); + break; + } + d_meters.at(2*i)->setPeakBar(lvls[0]); + d_meters.at(2*i+1)->setPeakBar(lvls[1]); + } +} + + +void RDMeterStrip::resizeEvent(QResizeEvent *e) +{ + int w=size().width(); + int h=size().height(); + int margin_x=(w-sizeHint().width())/2; + if(margin_x<0) { + margin_x=0; + } + int slot_w=sizeHint().width()/d_types.size(); + int meter_w=sizeHint().width()/(d_types.size()*3); + + for(int i=0;isetGeometry(margin_x+i*slot_w+slot_w/5, + 0, + meter_w, + h-20); + d_meters.at(2*i+1)->setGeometry(margin_x+i*slot_w+slot_w/2, + 0, + meter_w, + h-20); + d_labels.at(i)->setGeometry(margin_x+i*slot_w, + h-20, + slot_w, + 20); + } +} + + +void RDMeterStrip::paintEvent(QPaintEvent *) +{ + QPainter *p=new QPainter(this); + + p->fillRect(0,0,size().width(),size().height(),Qt::black); + + delete p; +} + + +void RDMeterStrip::AddMeter(int cardnum,int portnum,const QString &label) +{ + d_labels.push_back(new QLabel(label,this)); + d_labels.back()->setAlignment(Qt::AlignCenter); + d_labels.back()->setFont(labelFont()); + d_labels.back()->setStyleSheet("background-color: #000000;color: #FFFFFF"); + d_labels.back()->show(); + + d_meters.push_back(new RDPlayMeter(RDSegMeter::Up,this)); + d_meters.back()->setMode(RDSegMeter::Peak); + d_meters.back()->setFocusPolicy(Qt::NoFocus); + d_meters.back()->setLabel(tr("L")); + d_meters.back()->setRange(-4600,-800); + d_meters.back()->setHighThreshold(-1600); + d_meters.back()->setClipThreshold(-1100); + d_meters.back()->setSegmentSize(3); + d_meters.back()->setSegmentGap(1); + d_meters.back()->show(); + + d_meters.push_back(new RDPlayMeter(RDSegMeter::Up,this)); + d_meters.back()->setMode(RDSegMeter::Peak); + d_meters.back()->setFocusPolicy(Qt::NoFocus); + d_meters.back()->setLabel(tr("R")); + d_meters.back()->setRange(-4600,-800); + d_meters.back()->setHighThreshold(-1600); + d_meters.back()->setClipThreshold(-1100); + d_meters.back()->setSegmentSize(3); + d_meters.back()->setSegmentGap(1); + d_meters.back()->show(); + + setMinimumSize(sizeHint()); +} diff --git a/lib/rdmeterstrip.h b/lib/rdmeterstrip.h new file mode 100644 index 00000000..34770db4 --- /dev/null +++ b/lib/rdmeterstrip.h @@ -0,0 +1,64 @@ +// rdmeterstrip.h +// +// A strip of side-by-side vertical audio meters. +// +// (C) Copyright 2002-2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDMETERSTRIP_H +#define RDMETERSTRIP_H + +#include +#include + +#include +#include + +class RDMeterStrip : public RDWidget +{ + Q_OBJECT + public: + RDMeterStrip(QWidget *parent=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + void addInputMeter(int cardnum,int portnum,const QString &label); + void addOutputMeter(int cardnum,int portnum,const QString &label); + + private slots: + void pollData(); + + protected: + enum Type {Input=0,Output=1}; + void resizeEvent(QResizeEvent *e); + void paintEvent(QPaintEvent *); + + private: + void AddMeter(int cardnum,int portnum,const QString &label); + QList d_meters; + QList d_labels; + QList d_types; + QList d_card_numbers; + QList d_port_numbers; + QTimer *d_poll_timer; + + // QLabel *d_temp_label; +}; + + +#endif // RDMETERSTRIP_H diff --git a/tests/Makefile.am b/tests/Makefile.am index 8d9715af..2424de68 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,6 +42,7 @@ noinst_PROGRAMS = audio_convert_test\ log_unlink_test\ mcast_recv_test\ metadata_wildcard_test\ + meterstrip_test\ notification_test\ rdxml_parse_test\ readcd_test\ @@ -104,6 +105,10 @@ dist_metadata_wildcard_test_SOURCES = metadata_wildcard_test.cpp metadata_wildca nodist_metadata_wildcard_test_SOURCES = moc_metadata_wildcard_test.cpp metadata_wildcard_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT5_LIBS@ @MUSICBRAINZ_LIBS@ +dist_meterstrip_test_SOURCES = meterstrip_test.cpp meterstrip_test.h +nodist_meterstrip_test_SOURCES = moc_meterstrip_test.cpp +meterstrip_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT5_LIBS@ @MUSICBRAINZ_LIBS@ + dist_mcast_recv_test_SOURCES = mcast_recv_test.cpp mcast_recv_test.h nodist_mcast_recv_test_SOURCES = moc_mcast_recv_test.cpp mcast_recv_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT5_LIBS@ @MUSICBRAINZ_LIBS@ diff --git a/tests/meterstrip_test.cpp b/tests/meterstrip_test.cpp new file mode 100644 index 00000000..e00f091a --- /dev/null +++ b/tests/meterstrip_test.cpp @@ -0,0 +1,160 @@ +// meterstrip_test.cpp +// +// Test harness for RDWaveWidget +// +// (C) Copyright 2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +#include "meterstrip_test.h" + +MainWidget::MainWidget(QWidget *parent) + : QWidget(parent) +{ + QString err_msg; + bool ok=false; + + // + // Open the database + // + rda=new RDApplication("meterstrip_test","meterstrip_test",METERSTRIP_TEST_USAGE, + this); + if(!rda->open(&err_msg)) { + QMessageBox::critical(this,"meterstrip_test - "+tr("Error"),err_msg); + exit(RDApplication::ExitNoDb); + } + + // + // Get Command Switches + // + for(unsigned i=0;icmdSwitch()->keys();i++) { + if(rda->cmdSwitch()->key(i)=="--input-meter") { + QStringList f0=rda->cmdSwitch()->value(i).split(":",QString::KeepEmptyParts); + if(f0.size()<3) { + fprintf(stderr,"meterstrip_test: invalid --input-meter arguments\n"); + exit(RDApplication::ExitInvalidOption); + } + d_types.push_back(MainWidget::Input); + d_card_numbers.push_back(f0.at(0).toUInt(&ok)); + if(!ok) { + fprintf(stderr,"meterstrip_test: invalid card value\n"); + exit(RDApplication::ExitInvalidOption); + } + d_port_numbers.push_back(f0.at(1).toUInt(&ok)); + if(!ok) { + fprintf(stderr,"meterstrip_test: invalid port value\n"); + exit(RDApplication::ExitInvalidOption); + } + f0.removeFirst(); + f0.removeFirst(); + d_labels.push_back(f0.join(":")); + rda->cmdSwitch()->setProcessed(i,true); + } + if(rda->cmdSwitch()->key(i)=="--output-meter") { + QStringList f0=rda->cmdSwitch()->value(i).split(":",QString::KeepEmptyParts); + if(f0.size()<3) { + fprintf(stderr,"meterstrip_test: invalid --output-meter arguments\n"); + exit(RDApplication::ExitInvalidOption); + } + d_types.push_back(MainWidget::Output); + d_card_numbers.push_back(f0.at(0).toUInt(&ok)); + if(!ok) { + fprintf(stderr,"meterstrip_test: invalid card value\n"); + exit(RDApplication::ExitInvalidOption); + } + d_port_numbers.push_back(f0.at(1).toUInt(&ok)); + if(!ok) { + fprintf(stderr,"meterstrip_test: invalid port value\n"); + exit(RDApplication::ExitInvalidOption); + } + f0.removeFirst(); + f0.removeFirst(); + d_labels.push_back(f0.join(":")); + rda->cmdSwitch()->setProcessed(i,true); + } + if(!rda->cmdSwitch()->processed(i)) { + fprintf(stderr,"meterstrip_test: unknown option \"%s\"\"\n", + rda->cmdSwitch()->key(i).toUtf8().constData()); + exit(RDApplication::ExitInvalidOption); + } + } + + if(d_types.size()==0) { + fprintf(stderr,"at least one meter must be specified\n"); + exit(RDApplication::ExitInvalidOption); + } + + d_meter_stack=new RDMeterStrip(this); + + for(int i=0;iaddOutputMeter(d_card_numbers.at(i),d_port_numbers.at(i), + d_labels.at(i)); + break; + + case MainWidget::Input: + d_meter_stack-> + addInputMeter(d_card_numbers.at(i),d_port_numbers.at(i),d_labels.at(i)); + break; + } + } + setMinimumSize(d_meter_stack->sizeHint()); + + // + // Connect to caed(8) + // + connect(rda->cae(),SIGNAL(isConnected(bool)), + this,SLOT(caeConnectedData(bool))); + rda->cae()->connectHost(); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(d_meter_stack->sizeHint()); +} + + +void MainWidget::caeConnectedData(bool state) +{ + rda->cae()->enableMetering(&d_card_numbers); + // resize(d_meter_stack->sizeHint()); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + int w=size().width(); + int h=size().height(); + + d_meter_stack->setGeometry(0,0,w,h); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + MainWidget *w=new MainWidget(); + w->show(); + + return a.exec(); +} diff --git a/tests/meterstrip_test.h b/tests/meterstrip_test.h new file mode 100644 index 00000000..6490cbef --- /dev/null +++ b/tests/meterstrip_test.h @@ -0,0 +1,54 @@ +// meterstrip_test.h +// +// Test harness for RDMeterStrip +// +// (C) Copyright 2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef METERSTRIP_TEST_H +#define METERSTRIP_TEST_H + +#include +#include + +#include + +#define METERSTRIP_TEST_USAGE "--input-meter=::