summaryrefslogtreecommitdiff
path: root/src/rhlibrary/vumeter_widget.go
diff options
context:
space:
mode:
authorChristian Pointner <equinox@helsinki.at>2016-01-27 23:00:36 (GMT)
committerChristian Pointner <equinox@helsinki.at>2016-01-27 23:00:36 (GMT)
commitf02da6a0850b2115101fd5bbc3367135e80f4f54 (patch)
treeac95b80ae054a2523edaa07c98da1de0b1593da4 /src/rhlibrary/vumeter_widget.go
parentd05ebe8503985f65b918945b869f295a9595ca5e (diff)
moved vu meter to seperate file
Diffstat (limited to 'src/rhlibrary/vumeter_widget.go')
-rw-r--r--src/rhlibrary/vumeter_widget.go220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/rhlibrary/vumeter_widget.go b/src/rhlibrary/vumeter_widget.go
new file mode 100644
index 0000000..323e826
--- /dev/null
+++ b/src/rhlibrary/vumeter_widget.go
@@ -0,0 +1,220 @@
+//
+// rhlibrary
+//
+// The Radio Helsinki Rivendell Library
+//
+//
+// Copyright (C) 2016 Christian Pointner <equinox@helsinki.at>
+//
+// This file is part of rhlibrary.
+//
+// rhlibrary is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// rhlibrary 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 rhlibrary. If not, see <http://www.gnu.org/licenses/>.
+//
+
+package main
+
+import (
+ "time"
+
+ "code.helsinki.at/rhrd-go/player"
+ "github.com/gotk3/gotk3/glib"
+ "github.com/gotk3/gotk3/gtk"
+)
+
+const (
+ meterDBFloor float64 = 72 // -72 db is the lowest VU value
+ meterSegmentsGreen float64 = 21
+ meterSegmentsOrange float64 = 3
+ meterSegmentsRed float64 = 1
+ meterSegmentsTotal float64 = meterSegmentsGreen + meterSegmentsOrange + meterSegmentsRed
+)
+
+var (
+ meterBarCSS *gtk.CssProvider
+)
+
+func init() {
+ var err error
+ if meterBarCSS, err = gtk.CssProviderNew(); err != nil {
+ panic(err.Error())
+ }
+ err = meterBarCSS.LoadFromData(`
+.level-bar {
+ -GtkLevelBar-min-block-width: 13;
+ -GtkLevelBar-min-block-height: 8;
+}
+.level-bar.trough {
+ border: 0;
+ padding: 0;
+ border-radius: 0;
+ background-image: unset;
+}
+.level-bar.fill-block.level-green {
+ border-color: #006600;
+ background-image: linear-gradient(to bottom, #36B736, #006600);
+}
+.level-bar.fill-block.level-orange {
+ border-color: #AE6600;
+ background-image: linear-gradient(to bottom, #FFAC36, #AE6600);
+}
+.level-bar.fill-block.level-red {
+ border-color: #AE0000;
+ background-image: linear-gradient(to bottom, #FF3636, #AE0000);
+}`)
+ if err != nil {
+ panic(err.Error())
+ }
+}
+
+type vuMeterLevel struct {
+ green float64
+ orange float64
+ red float64
+}
+
+func (lvl *vuMeterLevel) setLevel(valdb float64) {
+ val := valdb + meterDBFloor
+ if val < 0 {
+ val = 0
+ } else {
+ val = (val / meterDBFloor) * meterSegmentsTotal
+ }
+
+ lvl.green = val
+ lvl.orange = val - meterSegmentsGreen
+ lvl.red = lvl.orange - meterSegmentsOrange
+ if lvl.orange < 0 {
+ lvl.orange = 0
+ }
+ if lvl.red < 0 {
+ lvl.red = 0
+ }
+ return
+}
+
+type vuMeter struct {
+ green *gtk.LevelBar
+ orange *gtk.LevelBar
+ red *gtk.LevelBar
+}
+
+func createMeterBar(segments float64) (bar *gtk.LevelBar, err error) {
+ if bar, err = gtk.LevelBarNewForInterval(0, segments); err != nil {
+ return
+ }
+ bar.SetMode(gtk.LEVEL_BAR_MODE_DISCRETE)
+ bar.RemoveOffsetValue(gtk.LEVEL_BAR_OFFSET_LOW)
+ bar.RemoveOffsetValue(gtk.LEVEL_BAR_OFFSET_HIGH)
+
+ var sc *gtk.StyleContext
+ if sc, err = bar.GetStyleContext(); err != nil {
+ return
+ }
+ sc.AddProvider(meterBarCSS, 600) // TOOD: hardcoded value
+ return
+}
+
+func newVUMeter() (meter *vuMeter, err error) {
+ meter = &vuMeter{}
+ if meter.green, err = createMeterBar(meterSegmentsGreen); err != nil {
+ return
+ }
+ if meter.orange, err = createMeterBar(meterSegmentsOrange); err != nil {
+ return
+ }
+ if meter.red, err = createMeterBar(meterSegmentsRed); err != nil {
+ return
+ }
+
+ meter.green.AddOffsetValue("green", 0)
+ meter.orange.AddOffsetValue("orange", 0)
+ meter.red.AddOffsetValue("red", 0)
+
+ return
+}
+
+func (m *vuMeter) SetValue(lvl *vuMeterLevel) {
+ m.green.SetValue(lvl.green)
+ m.orange.SetValue(lvl.orange)
+ m.red.SetValue(lvl.red)
+}
+
+func addVUMeterGrid(frame *gtk.Frame, p *player.PlayerChan) (err error) {
+ var grid *gtk.Grid
+ if grid, err = gtk.GridNew(); err != nil {
+ return
+ }
+ grid.SetRowSpacing(3)
+
+ var left, right *vuMeter
+ if left, err = newVUMeter(); err != nil {
+ return
+ }
+ if right, err = newVUMeter(); err != nil {
+ return
+ }
+
+ p.AddUpdateHandler(func(length time.Duration, pos time.Duration, meter player.Meter, userdata interface{}) bool {
+ glib.IdleAdd(func() {
+ ch := len(meter)
+ lval := &vuMeterLevel{0, 0, 0}
+ rval := &vuMeterLevel{0, 0, 0}
+ if ch >= 2 {
+ lval.setLevel(meter[0].Peak)
+ rval.setLevel(meter[1].Peak)
+ } else if ch == 1 {
+ lval.setLevel(meter[0].Peak)
+ rval = lval
+ }
+ left.SetValue(lval)
+ right.SetValue(rval)
+ })
+ return true
+ }, nil)
+
+ grid.Attach(left.green, 1, 1, 1, 1)
+ grid.Attach(left.orange, 2, 1, 1, 1)
+ grid.Attach(left.red, 3, 1, 1, 1)
+ grid.Attach(right.green, 1, 2, 1, 1)
+ grid.Attach(right.orange, 2, 2, 1, 1)
+ grid.Attach(right.red, 3, 2, 1, 1)
+
+ frame.Add(grid)
+ return
+}
+
+func getVUMeterWidget(p *player.PlayerChan) (gtk.IWidget, error) {
+ frame, err := gtk.FrameNew("")
+ if err != nil {
+ return nil, err
+ }
+
+ var cp *gtk.CssProvider
+ if cp, err = gtk.CssProviderNew(); err != nil {
+ return nil, err
+ }
+ if err = cp.LoadFromData(".frame { padding: 3px; }"); err != nil {
+ return nil, err
+ }
+ var sc *gtk.StyleContext
+ if sc, err = frame.GetStyleContext(); err != nil {
+ return nil, err
+ }
+ sc.AddProvider(cp, 600) // TOOD: hardcoded value
+
+ if err = addVUMeterGrid(frame, p); err != nil {
+ return nil, err
+ }
+ return frame, nil
+}