Indicator.cs

//**********************************************************

//* Direct X Sound Recorder                                *

//* Author: D. Zouchinski                                  *

//* http://zouchinski.co.uk                                *

//* Copyright @ 2009-2011                                  *

//**********************************************************

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Drawing;

using System.Data;

using System.Text;

using System.Windows.Forms;

 

namespace DZouch

{

    public partial class Indicator : UserControl

    {

        private double period = 0.3 * 44100;

        private double mean;

        private double meanPower;

        private double peakPower;

        private static short threshold = 30000;

        private double powerLimit = 2.0 * Math.Log10((double)threshold);

 

        public Indicator()

        {

            InitializeComponent();

            SetStyle(ControlStyles.ResizeRedraw, true);

            UpdateStyles();

        }

 

        protected override void OnPaint(PaintEventArgs e)

        {

            Rectangle rect = ClientRectangle;

            rect.Width -= 1;

            rect.Height -= 1;

 

            if (peakPower > powerLimit)

            {

                using (Brush brush = new SolidBrush(Color.Red))

                    e.Graphics.FillRectangle(brush, rect);

            }

 

            using (Pen pen = new Pen(Color.Blue))

                e.Graphics.DrawRectangle(pen, rect);

 

            rect.Inflate(-2, -2);

 

            int pos = ScalePower(rect, meanPower);

            using (Pen pen = new Pen(Color.Green))

            {

                for (int line = rect.Bottom; line >= pos; line -= 2)

                    e.Graphics.DrawLine(pen, rect.Left, line, rect.Right, line);

            }

 

            pos = ScalePower(rect, peakPower);

            using (Pen pen = new Pen(Color.Red))

                e.Graphics.DrawLine(pen, rect.Left, pos, rect.Right, pos);

 

            base.OnPaint(e);

        }

 

        private int ScalePower(Rectangle rect, double power)

        {

            // We will ignore noise of up to level of 100

            return ScalePosition(rect, Math.Max(0, power - 4), MaxPower - 4);

        }

 

        private int ScalePosition(Rectangle rect, double value, double max)

        {

            int pos = (int)(rect.Height * (value / max));

            if (pos > rect.Height)

                pos = rect.Height;

            if (pos < 0)

                pos = 0;

 

            pos = rect.Top + rect.Height - pos;

            return pos;

        }

 

        public void Update(short[] data)

        {

            if (data == null)

                return;

            if (data.Length == 0)

                return;

 

            double max = 0, square = 0;

            foreach (short sample in data)

            {

                if (Math.Abs((double)sample) > max)

                    max = Math.Abs((double)sample);

 

                double deviation = sample - mean;

                square += (deviation * deviation);

                mean += deviation / period;

            }

            square /= data.Length;

            meanPower += (Math.Log10(square + 1) - meanPower) * Math.Min(data.Length / period, 1);

            peakPower += (Math.Log10(max * max + 1) - peakPower) * Math.Min(data.Length / period, 1);

 

            Invalidate();

        }

 

        public double MeanPower { get { return meanPower; } }

 

        public double PeakPower { get { return peakPower; } }

 

        public double MaxPower { get { return Math.Log10(32768.0 * 32768.0 + 1); } }

 

        public void Reset()

        {

            mean = 0;

            meanPower = 0;

            peakPower = 0;

        }

    }

}