summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2004-09-06 17:50:31 +0000
committerLennart Poettering <lennart@poettering.net>2004-09-06 17:50:31 +0000
commit54e219fe520264406bc9c4962e57fde15d31711d (patch)
tree0f0a46bef4989b8976f5b3fee233e0c11a9dcb03
parent471d3a8e539cdd50e202e4c731f13ea66a5a8c24 (diff)
initial commit
git-svn-id: file:///home/lennart/svn/public/pavumeter/trunk@3 c62a5a7b-6fe3-0310-9d5a-afe6de46906b
-rw-r--r--src/Makefile8
-rw-r--r--src/vumeter.cc197
2 files changed, 205 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..d38d19d
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,8 @@
+
+all: pavumeter
+
+pavumeter: vumeter.cc
+ $(CXX) $^ -o $@ `pkg-config gtkmm-2.4 --cflags --libs` -I ../../polypaudio -lpolyp -lpolyp-mainloop-glib -L../../polypaudio/polyp/.libs -Wall -W -pipe -O0 -g
+
+clean:
+ rm -f *.o pavumeter
diff --git a/src/vumeter.cc b/src/vumeter.cc
new file mode 100644
index 0000000..bc6ad58
--- /dev/null
+++ b/src/vumeter.cc
@@ -0,0 +1,197 @@
+#include <signal.h>
+
+#include <gtkmm.h>
+#include <polyp/polyplib-context.h>
+#include <polyp/polyplib-stream.h>
+#include <polyp/glib-mainloop.h>
+
+class MainWindow : public Gtk::Window {
+
+public:
+ MainWindow(unsigned chan);
+ virtual ~MainWindow();
+
+protected:
+
+ class ChannelInfo {
+ public:
+ ChannelInfo(MainWindow &w, const Glib::ustring &l);
+ Gtk::Label *label;
+ Gtk::ProgressBar *progress;
+ };
+
+ Gtk::Table table;
+ std::vector<ChannelInfo*> channels;
+
+ virtual void addChannel(const Glib::ustring &l);
+
+public:
+ virtual void pushData(const float *d, size_t l);
+};
+
+MainWindow::MainWindow(unsigned nchan) :
+ Gtk::Window(),
+ table(1, 2) {
+
+ g_assert(nchan > 0);
+
+ set_border_width(12);
+ set_title("Volume Meter");
+ table.set_row_spacings(6);
+ table.set_col_spacings(12);
+ add(table);
+
+ if (nchan == 2) {
+ addChannel("<b>Left:</b>");
+ addChannel("<b>Right:</b>");
+ } else if (nchan == 1)
+ addChannel("<b>Level:</b>");
+ else {
+ for (unsigned i = 1; i <= nchan; i++) {
+ char t[40];
+ snprintf(t, sizeof(t), "<b>Channel #%u:</b>", i);
+ addChannel(t);
+ }
+ }
+
+ g_assert(channels.size() == nchan);
+
+ show_all();
+}
+
+MainWindow::~MainWindow() {
+ while (channels.size() > 0) {
+ ChannelInfo *i = channels.back();
+ channels.pop_back();
+ delete i;
+ }
+}
+
+void MainWindow::addChannel(const Glib::ustring &l) {
+ channels.push_back(new ChannelInfo(*this, l));
+}
+
+MainWindow::ChannelInfo::ChannelInfo(MainWindow &w, const Glib::ustring &l) {
+ label = Gtk::manage(new Gtk::Label(l, 1.0, 0.5));
+ label->set_markup(l);
+
+ progress = Gtk::manage(new Gtk::ProgressBar());
+ progress->set_fraction(0.5);
+
+ w.table.resize(w.channels.size()+1, 2);
+ w.table.attach(*label, 0, 1, w.channels.size(), w.channels.size()+1, Gtk::FILL, (Gtk::AttachOptions) 0);
+ w.table.attach(*progress, 1, 2, w.channels.size(), w.channels.size()+1, Gtk::EXPAND|Gtk::FILL, (Gtk::AttachOptions) 0);
+}
+
+void MainWindow::pushData(const float *d, unsigned samples) {
+ float *max;
+ unsigned nchan = channels.size();
+
+ max = (float*) g_malloc(sizeof(float)*nchan);
+ g_assert(max);
+
+ for (unsigned c = 0; c < nchan; c++)
+ max[c] = 0;
+
+ while (samples >= nchan) {
+
+ for (unsigned c = 0; c < nchan; c++) {
+ float v = fabs(d[c]);
+ if (v > max[c])
+ max[c] = v;
+ }
+
+ d += nchan;
+ samples -= nchan;
+ }
+
+ for (unsigned c = 0; c < nchan; c++) {
+ ChannelInfo *i = channels[c];
+ i->progress->set_fraction(max[c]);
+ }
+
+ g_free(max);
+}
+
+static MainWindow *mainWindow = NULL;
+static struct pa_context *context = NULL;
+static struct pa_stream *stream = NULL;
+static const struct pa_sample_spec sample_spec = {
+ PA_SAMPLE_FLOAT32, 44100, 2
+};
+
+static void stream_read_callback(struct pa_stream *, const void *p, size_t l, void *) {
+ g_assert(mainWindow);
+
+/* mainWindow->pushData((const float*) p, l/sizeof(float));*/
+}
+
+static void stream_state_callback(struct pa_stream *s, void *) {
+ switch (pa_stream_get_state(s)) {
+ case PA_STREAM_DISCONNECTED:
+ case PA_STREAM_CREATING:
+ break;
+
+ case PA_STREAM_READY:
+ g_assert(!mainWindow);
+ mainWindow = new MainWindow(sample_spec.channels);
+ break;
+
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ Gtk::Main::quit();
+ }
+}
+
+static void context_state_callback(struct pa_context *c, void *) {
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+
+ case PA_CONTEXT_READY:
+ g_assert(!stream);
+ stream = pa_stream_new(c, "vumeter", &sample_spec);
+ pa_stream_set_state_callback(stream, stream_state_callback, NULL);
+ pa_stream_set_read_callback(stream, stream_read_callback, NULL);
+ pa_stream_connect_record(stream, "input", NULL);
+ break;
+
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ Gtk::Main::quit();
+ }
+}
+
+int main(int argc, char *argv[]) {
+ struct pa_glib_mainloop *m;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ Gtk::Main kit(argc, argv);
+
+ m = pa_glib_mainloop_new(g_main_context_default());
+ g_assert(m);
+
+ context = pa_context_new(pa_glib_mainloop_get_api(m), "vumeter");
+ g_assert(m);
+
+ pa_context_set_state_callback(context, context_state_callback, NULL);
+ pa_context_connect(context, NULL);
+
+ Gtk::Main::run();
+
+ if (stream)
+ pa_stream_unref(stream);
+ if (context)
+ pa_context_unref(context);
+
+ if (mainWindow)
+ delete mainWindow;
+
+ pa_glib_mainloop_free(m);
+
+ return 0;
+}