Browse Source

Merge pull request #169 from hwdro/master

Simple volume meter widget
Jim 11 years ago
parent
commit
defceeef5d
3 changed files with 111 additions and 38 deletions
  1. 9 2
      libobs/obs-source.c
  2. 88 32
      obs/volume-control.cpp
  3. 14 4
      obs/volume-control.hpp

+ 9 - 2
libobs/obs-source.c

@@ -565,8 +565,15 @@ static void calc_volume_levels(struct obs_source *source, float *array,
 		max_val  = fmaxf(max_val, val_pow2);
 	}
 
-	rms_val = to_db(sqrtf(sum_val / (float)count * volume));
-	max_val = to_db(sqrtf(max_val * volume));
+	/*
+	  We want the volume meters scale linearly in respect to current
+	  volume, so, no need to apply volume here.
+	*/
+
+	UNUSED_PARAMETER(volume);
+
+	rms_val = to_db(sqrtf(sum_val / (float)count));
+	max_val = to_db(sqrtf(max_val));
 
 	if (max_val > source->vol_max)
 		source->vol_max = max_val;

+ 88 - 32
obs/volume-control.cpp

@@ -5,6 +5,7 @@
 #include <QVBoxLayout>
 #include <QSlider>
 #include <QLabel>
+#include <QPainter>
 #include <string>
 #include <math.h>
 
@@ -13,6 +14,12 @@ using namespace std;
 #define VOL_MIN -96.0f
 #define VOL_MAX  0.0f
 
+/* 
+	VOL_MIN_LOG = DBToLog(VOL_MIN)
+	VOL_MAX_LOG = DBToLog(VOL_MAX)
+	... just in case someone wants to use a smaller scale
+ */
+
 #define VOL_MIN_LOG -2.0086001717619175
 #define VOL_MAX_LOG -0.77815125038364363
 
@@ -40,18 +47,14 @@ void VolControl::OBSVolumeChanged(void *data, calldata_t calldata)
 void VolControl::OBSVolumeLevel(void *data, calldata_t calldata)
 {
 	VolControl *volControl = static_cast<VolControl*>(data);
-	float level = calldata_float(calldata, "level");
-	float mag   = calldata_float(calldata, "magnitude");
-
-	/*
-	 * TODO: an actual volume control that can process level, mag, peak.
-	 *
-	 * for the time being, just average level and magnitude.
-	 */
-	float result = (level + mag) * 0.5f;
+	float peak      = calldata_float(calldata, "level");
+	float mag       = calldata_float(calldata, "magnitude");
+	float peakHold  = calldata_float(calldata, "peak");
 
 	QMetaObject::invokeMethod(volControl, "VolumeLevel",
-		Q_ARG(float, result));
+		Q_ARG(float, mag),
+		Q_ARG(float, peak),
+		Q_ARG(float, peakHold));
 }
 
 void VolControl::VolumeChanged(int vol)
@@ -61,22 +64,21 @@ void VolControl::VolumeChanged(int vol)
 	signalChanged = true;
 }
 
-void VolControl::VolumeLevel(float level)
+void VolControl::VolumeLevel(float mag, float peak, float peakHold)
 {
 	uint64_t curMeterTime = os_gettime_ns() / 1000000;
 
-	levelTotal += level;
-	levelCount += 1.0f;
+	/*
+	   Add again peak averaging?
+	*/
 
 	/* only update after a certain amount of time */
 	if ((curMeterTime - lastMeterTime) > UPDATE_INTERVAL_MS) {
+		float vol = (float)slider->value() * 0.01f;
 		lastMeterTime = curMeterTime;
-
-		float finalLevel = levelTotal / levelCount;
-		volMeter->setValue(int(DBToLinear(finalLevel) * 10000.0f));
-
-		levelTotal = 0.0f;
-		levelCount = 0.0f;
+		volMeter->setLevels(DBToLinear(mag) * vol,
+				    DBToLinear(peak) * vol,
+				    DBToLinear(peakHold) * vol);
 	}
 }
 
@@ -118,7 +120,7 @@ VolControl::VolControl(OBSSource source_)
 
 	nameLabel = new QLabel();
 	volLabel  = new QLabel();
-	volMeter  = new QProgressBar();
+	volMeter  = new VolumeMeter();
 	slider    = new QSlider(Qt::Horizontal);
 
 	QFont font = nameLabel->font();
@@ -133,18 +135,6 @@ VolControl::VolControl(OBSSource source_)
 	slider->setValue(vol);
 //	slider->setMaximumHeight(13);
 
-	volMeter->setMaximumHeight(1);
-	volMeter->setMinimum(0);
-	volMeter->setMaximum(10000);
-	volMeter->setTextVisible(false);
-
-	/* [Danni] Temporary color. */
-	QString testColor = "QProgressBar "
-	                    "{border: 0px} "
-	                    "QProgressBar::chunk "
-	                    "{width: 1px; background-color: #AA0000;}";
-	volMeter->setStyleSheet(testColor);
-
 	textLayout->setContentsMargins(0, 0, 0, 0);
 	textLayout->addWidget(nameLabel);
 	textLayout->addWidget(volLabel);
@@ -177,3 +167,69 @@ VolControl::~VolControl()
 	signal_handler_disconnect(obs_source_signalhandler(source),
 		"volume_level", OBSVolumeLevel, this);
 }
+
+VolumeMeter::VolumeMeter(QWidget *parent)
+			: QWidget(parent)
+{
+	setMinimumSize(1, 3);
+
+	bkColor.setRgb(0xDD, 0xDD, 0xDD);
+	magColor.setRgb(0x20, 0x7D, 0x17);
+	peakColor.setRgb(0x3E, 0xF1, 0x2B);
+	peakHoldColor.setRgb(0x00, 0x00, 0x00);
+	
+
+	setLevels(0.0f, 0.0f, 0.0f);
+}
+
+void VolumeMeter::setLevels(float nmag, float npeak, float npeakHold)
+{
+	mag      = nmag;
+	peak     = npeak;
+	peakHold = npeakHold;
+	update();
+}
+
+void VolumeMeter::paintEvent(QPaintEvent *event)
+{
+	UNUSED_PARAMETER(event);
+
+	QPainter painter(this);
+	QLinearGradient gradient;
+
+	int width  = size().width();
+	int height = size().height();
+
+	int scaledMag      = int((float)width * mag);
+	int scaledPeak     = int((float)width * peak);
+	int scaledPeakHold = int((float)width * peakHold);
+
+	gradient.setStart(qreal(scaledMag), 0);
+	gradient.setFinalStop(qreal(scaledPeak), 0);
+	gradient.setColorAt(0, magColor);
+	gradient.setColorAt(1, peakColor);
+
+	// RMS
+	painter.fillRect(0, 0, 
+			scaledMag, height,
+			magColor);
+
+	// RMS - Peak gradient
+	painter.fillRect(scaledMag, 0,
+			scaledPeak - scaledMag + 1, height,
+			QBrush(gradient));
+
+	// Background
+	painter.fillRect(scaledPeak, 0,
+			width - scaledPeak, height,
+			bkColor);
+
+	// Peak hold
+	if(peakHold == 1.0f)
+		scaledPeakHold--;
+
+	painter.setPen(peakHoldColor);
+	painter.drawLine(scaledPeakHold, 0,
+		scaledPeakHold, height);
+
+}

+ 14 - 4
obs/volume-control.hpp

@@ -2,9 +2,19 @@
 
 #include <obs.hpp>
 #include <QWidget>
-#include <QProgressBar>
 
-/* TODO: Make a real volume control that isn't terrible */
+class VolumeMeter : public QWidget
+{
+	Q_OBJECT
+private:
+	float mag, peak, peakHold;
+	QColor bkColor, magColor, peakColor, peakHoldColor;
+public:
+	explicit VolumeMeter(QWidget *parent = 0);
+	void setLevels(float nmag, float npeak, float npeakHold);
+protected:
+	void paintEvent(QPaintEvent *event);
+};
 
 class QLabel;
 class QSlider;
@@ -16,7 +26,7 @@ private:
 	OBSSource source;
 	QLabel          *nameLabel;
 	QLabel          *volLabel;
-	QProgressBar    *volMeter;
+	VolumeMeter     *volMeter;
 	QSlider         *slider;
 	bool            signalChanged;
 	uint64_t        lastMeterTime;
@@ -28,7 +38,7 @@ private:
 
 private slots:
 	void VolumeChanged(int vol);
-	void VolumeLevel(float level);
+	void VolumeLevel(float mag, float peak, float peakHold);
 	void SliderChanged(int vol);
 
 public: