Logo Search packages:      
Sourcecode: vat version File versions  Download package

vu.cc

/*
 * Copyright (c) 1990-1994 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the Computer Systems
 *    Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
static const char rcsid[] =
    "@(#) $Header: vu.cc,v 1.16 96/03/16 13:12:55 van Exp $ (LBL)";

#include "config.h"
#include <math.h>
#include "vu.h"
#include "Tcl.h"

int VUMeter::command(int argc, const char*const* argv)
{
      if (argc == 3) {
            if (strcmp(argv[1], "set") == 0) {
                  set(atof(argv[2]));
                  redraw();
                  return (TCL_OK);
            }
      }
      return (TkWidget::command(argc, argv));
}

void VUMeter::resize()
{
      topblk_ = peak_ = 0;
      setpeak_ = 0;
      peakcnt_ = 0;
      ntop_ = 0;
      nlevel_ = int(height_ / barht_);
      const char* hotLevel = Tk_GetOption(tk_, "hotLevel", "VatVU");
      hot_level_ = nlevel_ * atoi(hotLevel) / 100;
}

inline void VUMeter::rect(Display* dpy, Drawable win, GC gc,
                    int x, int y, int w, int h) const
{
      XFillRectangle(dpy, win, gc,
                   x, height_ - y - h, w, h);
}

void VUMeter::draw()
{
      Display* dpy = Tk_Display(tk_);
      Drawable window = Tk_WindowId(tk_);
      int w = width_ - 2 * gap_;

      rect(dpy, window, bg_, 0, 0, width_, height_);
      int y = 0;
      for (int i = 0; i < topblk_; ++i) {
            rect(dpy, window, fg_, gap_, y, w, barht_ - gap_);
            y += barht_;
      }
      if (peak_ > 0) {
            y = (peak_ - 1) * barht_;
            GC gc = (peak_ >= hot_level_) ? hot_ : gray_;
            rect(dpy, window, gc, gap_, y, w, barht_ - gap_);
      }
}

void VUMeter::update()
{
      int w = width_ - 2 * gap_;
      int lblk = topblk_;
      int tblk = ntop_;
      int dif = tblk - topblk_;
      if (dif == 0)
            return;
      topblk_ = tblk;
      Display* dpy = Tk_Display(tk_);
      Drawable window = Tk_WindowId(tk_);
      if (dif < 0) {
            /* lblk is above tblk */
            int ymin = tblk * barht_;
            int ymax = lblk * barht_;
            if (lblk == peak_)
                  ymax -= barht_;
            int h = ymax - ymin;
            if (h > 0)
                  rect(dpy, window, bg_, gap_, ymin, w, h);
            if (setpeak_) {
                  if (tblk == 0)
                        return;
                  setpeak_ = 0;
                  int y = (peak_ - 1) * barht_;
                  rect(dpy, window, bg_, gap_, y, w, barht_ - gap_);
                  peak_ = tblk;
                  y = (tblk - 1) * barht_;
                  if (mono_)
                        /*
                         * For mono, need to clear background
                         * first since we do a stippled fill.
                         */
                        rect(dpy, window, bg_,
                             gap_, y, w, barht_ - gap_);
                  GC gc = (tblk >= hot_level_) ? hot_ : gray_;
                  rect(dpy, window, gc, gap_, y, w, barht_ - gap_);
            }
            return;
      }
      if (peak_ < tblk) {
            setpeak_ = 0;
            peak_ = tblk;
            int y = (tblk - 1) * barht_;
            GC gc = (tblk >= hot_level_) ? hot_ : gray_;
            rect(dpy, window, gc, gap_, y, w, barht_ - gap_);
      }
      if (tblk == peak_)
            --tblk;
      if (lblk > 0)
            /*
             * Start one lower than we have to since the old
             * top block might be the peak indicator.
             */
            --lblk;

      int y = lblk * barht_;
      for (int i = lblk + 1; i <= tblk; ++i) {
            rect(dpy, window, fg_, gap_, y, w, barht_ - gap_);
            y += barht_;
      }
}

GC VUMeter::bg_;
GC VUMeter::fg_;
GC VUMeter::gray_;
GC VUMeter::hot_;

VUMeter::VUMeter(const char* path, double s, double f, int width) :
      TkWidget(path, "VatVU", width, 100),
      value_(0.),
      alpha_(f),
      scale_(s),
      barht_(width / 2),
      gap_(2),
      nlevel_(0),
      hot_level_(0),
      topblk_(0),
      ntop_(0),
      peak_(0),
      peakcnt_(0),
      setpeak_(0)
{
      if (bg_ == 0) {
            Tk_Uid bg = Tk_GetOption(tk_, "background", "VatVU");
            Tk_Uid fg = Tk_GetOption(tk_, "foreground", "VatVU");
            Tk_Uid gr = Tk_GetOption(tk_, "peak", "VatVU");
            Tk_Uid hot = Tk_GetOption(tk_, "hot", "VatVU");

            bg_ = lookup_gc(0, bg, bg);
            fg_ = lookup_gc(0, fg, bg);
            gray_ = lookup_gc(0, gr, bg);
            hot_ = lookup_gc(0, hot, bg);
            if (hot_ == 0)
                  /*XXX error message */
                  hot_ = fg_;
      }
}

void VUMeter::set(double d)
{
      d = warp(d);
      d *= scale_;
      if (d > 1.0)
            d = 1.0;
      else if (d < 0.0)
            d = 0.0;

      register double v = value_;
      v += alpha_ * (d - v);
      value_ = v;
      int nblk = int(double(nlevel_) * v + 0.5);
      if (nblk != ntop_) {
            ntop_ = nblk;
            if (--peakcnt_ < 0) {
                  peakcnt_ = 25;
                  setpeak_ = 1;
            }
            /*
             * Call update() here instead of redraw() since the meter
             * needs to be animated in real-time.  Using redraw
             * makes for very sluggish action.
             */
            if (Tk_IsMapped(tk_)) {
#ifdef notdef
                  /*XXX can't do this because damage_ is private */
                  damage_ = 0;
#endif
                  update();
            }
      }
}

DBMeter::DBMeter(const char* path,
             double scale, double lpfgain, int width)
      : VUMeter(path, 1 / log10(scale), lpfgain, width)
{
}

double DBMeter::warp(double d) const
{
      if (d != 0.) {
            if (d < 0)
                  d = -d;
            d = log10(d);
      }
      return (d);
}

LinearMeter::LinearMeter(const char* path,
                   double scale, double lpfgain, int width)
      : VUMeter(path, scale, lpfgain, width)
{
}

double LinearMeter::warp(double d) const
{
      if (d < 0)
            d = -d;
      return (d);
}

static class MeterCommand : public TclObject {
public:
      MeterCommand() : TclObject("meter") {}
      virtual int command(int argc, const char*const* argv);
} meter_command;

int MeterCommand::command(int argc, const char*const* argv)
{
      Tcl& tcl = Tcl::instance();
      if (argc == 2) {
            /*
             * the value '81' for meter full scale is because we want to
             * peg the meter if the peak amplitude of some tone hits the
             * u-law clipping level (127).  Since the mean of abs(sin(x))
             * over an integral number of periods is 2/pi, the meter
             * fullscale is set to 127*2/3.14 = 81.
             */
            LinearMeter* p = new LinearMeter(argv[1], 1./81., 0.75, 20);
            tcl.result(p->name());
            return (TCL_OK);
      }
      return (TclObject::command(argc, argv));
}

Generated by  Doxygen 1.6.0   Back to index