volume-control.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include "volume-control.hpp"
  2. #include "qt-wrappers.hpp"
  3. #include <util/platform.h>
  4. #include <QHBoxLayout>
  5. #include <QVBoxLayout>
  6. #include <QSlider>
  7. #include <QLabel>
  8. #include <QPainter>
  9. #include <string>
  10. #include <math.h>
  11. using namespace std;
  12. #define VOL_MIN -96.0f
  13. #define VOL_MAX 0.0f
  14. /*
  15. VOL_MIN_LOG = DBToLog(VOL_MIN)
  16. VOL_MAX_LOG = DBToLog(VOL_MAX)
  17. ... just in case someone wants to use a smaller scale
  18. */
  19. #define VOL_MIN_LOG -2.0086001717619175
  20. #define VOL_MAX_LOG -0.77815125038364363
  21. #define UPDATE_INTERVAL_MS 50
  22. static inline float DBToLog(float db)
  23. {
  24. return -log10f(0.0f - (db - 6.0f));
  25. }
  26. static inline float DBToLinear(float db_full)
  27. {
  28. float db = fmaxf(fminf(db_full, VOL_MAX), VOL_MIN);
  29. return (DBToLog(db) - VOL_MIN_LOG) / (VOL_MAX_LOG - VOL_MIN_LOG);
  30. }
  31. void VolControl::OBSVolumeChanged(void *data, calldata_t calldata)
  32. {
  33. VolControl *volControl = static_cast<VolControl*>(data);
  34. int vol = (int)(calldata_float(calldata, "volume") * 100.0f + 0.5f);
  35. QMetaObject::invokeMethod(volControl, "VolumeChanged", Q_ARG(int, vol));
  36. }
  37. void VolControl::OBSVolumeLevel(void *data, calldata_t calldata)
  38. {
  39. VolControl *volControl = static_cast<VolControl*>(data);
  40. float peak = calldata_float(calldata, "level");
  41. float mag = calldata_float(calldata, "magnitude");
  42. float peakHold = calldata_float(calldata, "peak");
  43. QMetaObject::invokeMethod(volControl, "VolumeLevel",
  44. Q_ARG(float, mag),
  45. Q_ARG(float, peak),
  46. Q_ARG(float, peakHold));
  47. }
  48. void VolControl::VolumeChanged(int vol)
  49. {
  50. signalChanged = false;
  51. slider->setValue(vol);
  52. signalChanged = true;
  53. }
  54. void VolControl::VolumeLevel(float mag, float peak, float peakHold)
  55. {
  56. uint64_t curMeterTime = os_gettime_ns() / 1000000;
  57. /*
  58. Add again peak averaging?
  59. */
  60. /* only update after a certain amount of time */
  61. if ((curMeterTime - lastMeterTime) > UPDATE_INTERVAL_MS) {
  62. float vol = (float)slider->value() * 0.01f;
  63. lastMeterTime = curMeterTime;
  64. volMeter->setLevels(DBToLinear(mag) * vol,
  65. DBToLinear(peak) * vol,
  66. DBToLinear(peakHold) * vol);
  67. }
  68. }
  69. void VolControl::SliderChanged(int vol)
  70. {
  71. if (signalChanged) {
  72. signal_handler_disconnect(obs_source_signalhandler(source),
  73. "volume", OBSVolumeChanged, this);
  74. obs_source_setvolume(source, float(vol)*0.01f);
  75. signal_handler_connect(obs_source_signalhandler(source),
  76. "volume", OBSVolumeChanged, this);
  77. }
  78. volLabel->setText(QString::number(vol));
  79. }
  80. QString VolControl::GetName() const
  81. {
  82. return nameLabel->text();
  83. }
  84. void VolControl::SetName(const QString &newName)
  85. {
  86. nameLabel->setText(newName);
  87. }
  88. VolControl::VolControl(OBSSource source_)
  89. : source (source_),
  90. signalChanged (true),
  91. lastMeterTime (0),
  92. levelTotal (0.0f),
  93. levelCount (0.0f)
  94. {
  95. QVBoxLayout *mainLayout = new QVBoxLayout();
  96. QHBoxLayout *textLayout = new QHBoxLayout();
  97. int vol = int(obs_source_getvolume(source) * 100.0f);
  98. nameLabel = new QLabel();
  99. volLabel = new QLabel();
  100. volMeter = new VolumeMeter();
  101. slider = new QSlider(Qt::Horizontal);
  102. QFont font = nameLabel->font();
  103. font.setPointSize(font.pointSize()-1);
  104. nameLabel->setText(obs_source_getname(source));
  105. nameLabel->setFont(font);
  106. volLabel->setText(QString::number(vol));
  107. volLabel->setFont(font);
  108. slider->setMinimum(0);
  109. slider->setMaximum(100);
  110. slider->setValue(vol);
  111. // slider->setMaximumHeight(13);
  112. textLayout->setContentsMargins(0, 0, 0, 0);
  113. textLayout->addWidget(nameLabel);
  114. textLayout->addWidget(volLabel);
  115. textLayout->setAlignment(nameLabel, Qt::AlignLeft);
  116. textLayout->setAlignment(volLabel, Qt::AlignRight);
  117. mainLayout->setContentsMargins(4, 4, 4, 4);
  118. mainLayout->setSpacing(2);
  119. mainLayout->addItem(textLayout);
  120. mainLayout->addWidget(volMeter);
  121. mainLayout->addWidget(slider);
  122. setLayout(mainLayout);
  123. signal_handler_connect(obs_source_signalhandler(source),
  124. "volume", OBSVolumeChanged, this);
  125. signal_handler_connect(obs_source_signalhandler(source),
  126. "volume_level", OBSVolumeLevel, this);
  127. QWidget::connect(slider, SIGNAL(valueChanged(int)),
  128. this, SLOT(SliderChanged(int)));
  129. }
  130. VolControl::~VolControl()
  131. {
  132. signal_handler_disconnect(obs_source_signalhandler(source),
  133. "volume", OBSVolumeChanged, this);
  134. signal_handler_disconnect(obs_source_signalhandler(source),
  135. "volume_level", OBSVolumeLevel, this);
  136. }
  137. VolumeMeter::VolumeMeter(QWidget *parent)
  138. : QWidget(parent)
  139. {
  140. setMinimumSize(1, 3);
  141. bkColor.setRgb(0xDD, 0xDD, 0xDD);
  142. magColor.setRgb(0x20, 0x7D, 0x17);
  143. peakColor.setRgb(0x3E, 0xF1, 0x2B);
  144. peakHoldColor.setRgb(0x00, 0x00, 0x00);
  145. setLevels(0.0f, 0.0f, 0.0f);
  146. }
  147. void VolumeMeter::setLevels(float nmag, float npeak, float npeakHold)
  148. {
  149. mag = nmag;
  150. peak = npeak;
  151. peakHold = npeakHold;
  152. update();
  153. }
  154. void VolumeMeter::paintEvent(QPaintEvent *event)
  155. {
  156. UNUSED_PARAMETER(event);
  157. QPainter painter(this);
  158. QLinearGradient gradient;
  159. int width = size().width();
  160. int height = size().height();
  161. int scaledMag = int((float)width * mag);
  162. int scaledPeak = int((float)width * peak);
  163. int scaledPeakHold = int((float)width * peakHold);
  164. gradient.setStart(qreal(scaledMag), 0);
  165. gradient.setFinalStop(qreal(scaledPeak), 0);
  166. gradient.setColorAt(0, magColor);
  167. gradient.setColorAt(1, peakColor);
  168. // RMS
  169. painter.fillRect(0, 0,
  170. scaledMag, height,
  171. magColor);
  172. // RMS - Peak gradient
  173. painter.fillRect(scaledMag, 0,
  174. scaledPeak - scaledMag + 1, height,
  175. QBrush(gradient));
  176. // Background
  177. painter.fillRect(scaledPeak, 0,
  178. width - scaledPeak, height,
  179. bkColor);
  180. // Peak hold
  181. if(peakHold == 1.0f)
  182. scaledPeakHold--;
  183. painter.setPen(peakHoldColor);
  184. painter.drawLine(scaledPeakHold, 0,
  185. scaledPeakHold, height);
  186. }