]> git.sesse.net Git - nageru/commitdiff
Add the beginnings of a very simple VU meter, based on libebur128.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 28 Oct 2015 23:48:08 +0000 (00:48 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 29 Oct 2015 19:35:52 +0000 (20:35 +0100)
Makefile
glwidget.cpp
mainwindow.cpp
mixer.cpp
mixer.h
ui_mainwindow.ui
vumeter.cpp [new file with mode: 0644]
vumeter.h [new file with mode: 0644]

index d056084f98e0ede035a5fd87507ffa59dd5ec4e9..23551947e09569e58003435f5b55c0ab7965eddf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
 CXX=g++
 PKG_MODULES = Qt5Core Qt5Gui Qt5Widgets Qt5OpenGLExtensions Qt5OpenGL libusb-1.0 movit lua5.2 libmicrohttpd
 CXXFLAGS := -O2 -march=native -g -std=gnu++11 -Wall -Wno-deprecated-declarations -Werror -fPIC $(shell pkg-config --cflags $(PKG_MODULES)) -pthread -DMOVIT_SHADER_DIR=\"$(shell pkg-config --variable=shaderdir movit)\"
-LDFLAGS=$(shell pkg-config --libs $(PKG_MODULES)) -lEGL -lGL -pthread -lva -lva-drm -lva-x11 -lX11 -lavformat -lavcodec -lavutil -lzita-resampler
+LDFLAGS=$(shell pkg-config --libs $(PKG_MODULES)) -lEGL -lGL -pthread -lva -lva-drm -lva-x11 -lX11 -lavformat -lavcodec -lavutil -lzita-resampler -lebur128
 
 # Qt objects
-OBJS=glwidget.o main.o mainwindow.o window.o
-OBJS += glwidget.moc.o mainwindow.moc.o window.moc.o
+OBJS=glwidget.o main.o mainwindow.o window.o vumeter.o
+OBJS += glwidget.moc.o mainwindow.moc.o window.moc.o vumeter.moc.o
 
 # Mixer objects
 OBJS += h264encode.o mixer.o bmusb/bmusb.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampler.o httpd.o
index 3482a13391609c049869650d7aadb32481cb94ec..2118ffe1c6dff368cc9b30604cead5b8af8bf7d0 100644 (file)
@@ -3,6 +3,7 @@
 #include <qtextstream.h>  // Needs to come before egl.h.
 #include <qcursor.h>  // Needs to come before egl.h.
 #include <qcoreevent.h>  // Needs to come before egl.h.
+#include <qevent.h>  // Needs to come before egl.h.
 #include <epoxy/gl.h>
 #include <epoxy/egl.h>
 #include <QSurfaceFormat>
@@ -17,6 +18,7 @@
 #include "context.h"
 #include "mixer.h"
 #include "ref_counted_gl_sync.h"
+#include "vumeter.h"
 
 class MainWindow;
 class QSurface;
@@ -46,6 +48,9 @@ void GLWidget::initializeGL()
        static std::once_flag flag;
        std::call_once(flag, [this]{
                global_mixer = new Mixer(QGLFormat::toSurfaceFormat(format()));
+               global_mixer->set_audio_level_callback([this](float level){
+                       global_vu_meter->set_level(level);
+               });
                global_mixer->start();
        });
        global_mixer->set_frame_ready_callback(output, [this]{
index 3ccc89303dd946dc1ff5a1ed1bde37582f048cd8..29a863b2456ea568f36e014ae878df607884b753 100644 (file)
@@ -79,6 +79,8 @@ MainWindow::MainWindow()
        qRegisterMetaType<std::vector<std::string>>("std::vector<std::string>");
        connect(ui->preview1, SIGNAL(transition_names_updated(std::vector<std::string>)),
                this, SLOT(set_transition_names(std::vector<std::string>)));
+
+       global_vu_meter = ui->vu_meter;  // global_mixer does not exist yet, so need to delay the hookup.
 }
 
 void MainWindow::resizeEvent(QResizeEvent* event)
index 59f520aacdc12a0dbc70998c13da3df890a72a8c..226d57fbc741acc7101c4136f37e813b5bd491bd 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -146,6 +146,8 @@ Mixer::Mixer(const QSurfaceFormat &format)
                "    gl_FragColor = texture2D(cbcr_tex, tc0); \n"
                "} \n";
        cbcr_program_num = resource_pool->compile_glsl_program(cbcr_vert_shader, cbcr_frag_shader);
+
+       r128_state = ebur128_init(2, 48000, EBUR128_MODE_SAMPLE_PEAK | EBUR128_MODE_M | EBUR128_MODE_S | EBUR128_MODE_I | EBUR128_MODE_LRA);
 }
 
 Mixer::~Mixer()
@@ -161,6 +163,8 @@ Mixer::~Mixer()
                }
                cards[card_index].usb->stop_dequeue_thread();
        }
+
+       ebur128_destroy(&r128_state);
 }
 
 namespace {
@@ -352,6 +356,7 @@ void Mixer::thread_func()
                                        }
                                }
                                if (card_index == 0) {
+                                       ebur128_add_frames_float(r128_state, samples_out.data(), samples_out.size() / 2);
                                        h264_encoder->add_audio(pts_int, move(samples_out));
                                }
                        }
@@ -362,6 +367,12 @@ void Mixer::thread_func()
                        }
                }
 
+               if (audio_level_callback != nullptr) {
+                       double loudness_s;
+                       ebur128_loudness_shortterm(r128_state, &loudness_s);
+                       audio_level_callback(loudness_s);
+               }       
+
                // If the first card is reporting a corrupted or otherwise dropped frame,
                // just increase the pts (skipping over this frame) and don't try to compute anything new.
                if (card_copy[0].new_frame->len == 0) {
diff --git a/mixer.h b/mixer.h
index a177854b46cde0229ebfcb669998afea709813b7..5b82b4e962fe0191d1b0c8b443e71aea4b01c8b0 100644 (file)
--- a/mixer.h
+++ b/mixer.h
@@ -7,6 +7,7 @@
 #undef Success
 #include <movit/effect_chain.h>
 #include <movit/flat_input.h>
+#include <ebur128.h>
 #include <functional>
 
 #include "bmusb/bmusb.h"
@@ -80,6 +81,12 @@ public:
                output_channel[output].set_frame_ready_callback(callback);
        }
 
+       typedef std::function<void(float)> audio_level_callback_t;
+       void set_audio_level_callback(audio_level_callback_t callback)
+       {
+               audio_level_callback = callback;
+       }
+
        std::vector<std::string> get_transition_names()
        {
                return theme->get_transition_names(pts());
@@ -155,6 +162,9 @@ private:
 
        std::thread mixer_thread;
        bool should_quit = false;
+
+       audio_level_callback_t audio_level_callback = nullptr;
+       ebur128_state *r128_state = nullptr;
 };
 
 extern Mixer *global_mixer;
index 90663b09abd77fb9ea90a6cc256c26e212b92a86..12e386485147b6ef985a3dbafbfca6c4d23d1e3f 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>902</width>
-    <height>590</height>
+    <width>1089</width>
+    <height>664</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -27,7 +27,7 @@
     <item row="0" column="0">
      <layout class="QVBoxLayout" name="vertical_layout" stretch="0,0,0">
       <item>
-       <layout class="QHBoxLayout" name="me_displays" stretch="0,0,0">
+       <layout class="QHBoxLayout" name="me_displays" stretch="0,0,0,0">
         <item>
          <layout class="QVBoxLayout" name="verticalLayout_3">
           <property name="leftMargin">
           </item>
          </layout>
         </item>
+        <item>
+         <widget class="VUMeter" name="vu_meter" native="true">
+          <property name="minimumSize">
+           <size>
+            <width>30</width>
+            <height>0</height>
+           </size>
+          </property>
+         </widget>
+        </item>
        </layout>
       </item>
       <item>
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>902</width>
+     <width>1089</width>
      <height>19</height>
     </rect>
    </property>
    <extends>QWidget</extends>
    <header>qglwidget.h</header>
   </customwidget>
+  <customwidget>
+   <class>VUMeter</class>
+   <extends>QWidget</extends>
+   <header>vumeter.h</header>
+   <container>1</container>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
diff --git a/vumeter.cpp b/vumeter.cpp
new file mode 100644 (file)
index 0000000..03a93e7
--- /dev/null
@@ -0,0 +1,33 @@
+#include <QPainter>
+
+#include "vumeter.h"
+
+using namespace std;
+
+VUMeter *global_vu_meter = nullptr;
+
+VUMeter::VUMeter(QWidget *parent)
+       : QWidget(parent)
+{
+}
+
+void VUMeter::paintEvent(QPaintEvent *event)
+{
+       QPainter painter(this);
+
+       painter.fillRect(0, 0, width(), height(), Qt::black);
+
+       float level;
+       {
+               unique_lock<mutex> lock(level_mutex);
+               level = this->level;
+       }
+
+       const float min_level = 0.0f;    // y=0 is top of screen, so “min” is the loudest level.
+       const float max_level = -60.0f; 
+       int y = lrintf(height() * (level - min_level) / (max_level - min_level));
+       if (y >= 0 && y < height()) {
+               painter.setPen(Qt::white);
+               painter.drawLine(0, y, width(), y);
+       }
+}
diff --git a/vumeter.h b/vumeter.h
new file mode 100644 (file)
index 0000000..de27529
--- /dev/null
+++ b/vumeter.h
@@ -0,0 +1,31 @@
+#ifndef VUMETER_H
+#define VUMETER_H
+
+#include <QWidget>
+#include <QPaintEvent>
+
+#include <mutex>
+
+class VUMeter : public QWidget
+{
+       Q_OBJECT
+
+public:
+       VUMeter(QWidget *parent);
+
+       void set_level(float level) {
+               std::unique_lock<std::mutex> lock(level_mutex);
+               this->level = level;
+               update();
+       }
+
+private:
+       void paintEvent(QPaintEvent *event) override;
+
+       std::mutex level_mutex;
+       float level = -HUGE_VAL;
+};
+
+extern VUMeter *global_vu_meter;
+
+#endif