Commits

Mark Heath  committed 8ee9280

refactored to split peak finding, point creation and bezier geometry creation

  • Participants
  • Parent commits 1b42ba8

Comments (0)

Files changed (5)

File WpfWaveform/AutoSizeCanvas.cs

             foreach (var child in Children.OfType<FrameworkElement>())
             {
                 child.Measure(availableSize);
-                double x = x = GetLeft(child) + child.DesiredSize.Width; 
+                double left = GetLeft(child);
+                if (double.IsNaN(left)) left = 0;
+                double x = left + child.DesiredSize.Width; 
                 if (!double.IsInfinity(x) && !double.IsNaN(x))
                 {
                     width = Math.Max(width, x);
                 }
-                double y = GetTop(child) + child.DesiredSize.Height;
+                double top = GetTop(child);
+                if (double.IsNaN(top)) top = 0;
+
+                double y = top + child.DesiredSize.Height;
                 if (!double.IsInfinity(y) && !double.IsNaN(y))
                 {
                     height = Math.Max(height, y);

File WpfWaveform/BezierSpline.cs

         /// <param name="firstControlPoints">Output First Control points array of knots.Length - 1 length.</param>
         /// <param name="secondControlPoints">Output Second Control points array of knots.Length - 1 length.</param>
         /// <exception cref="ArgumentNullException"><paramref name="knots"/> parameter must be not null.</exception>
-        /// <exception cref="ArgumentException"><paramref name="knots"/> array must containg at least two points.</exception>
+        /// <exception cref="ArgumentException"><paramref name="knots"/> array must contain at least two points.</exception>
         public static void GetCurveControlPoints(Point[] knots, out Point[] firstControlPoints, out Point[] secondControlPoints)
         {
             if (knots == null)

File WpfWaveform/MainWindow.xaml.cs

 
         void MainWindow_Loaded(object sender, RoutedEventArgs e)
         {
-            using (var reader = new Mp3FileReader(@"E:\Audio\Music\Coldplay\X&Y\04-Fix You.mp3"))
-            {
-                int stepSize = reader.WaveFormat.AverageBytesPerSecond / 5;
-                byte[] byteBuffer = new byte[stepSize];
-                WaveBuffer buffer = new WaveBuffer(byteBuffer);
-                int read;
-                List<Point> points = new List<Point>();
-                int x = 0;
-                while ((read = reader.Read(byteBuffer, 0, stepSize)) > 0)
-                {
-                    int samples = read / 2; // assume 16 bit
-                    double maxLeft = 0;
-                    for (int sample = 0; sample < samples; sample+=2)
-                    {
-                        double sampleLeft = buffer.ShortBuffer[sample] / 32768.0;
-                        double sampleRight = buffer.ShortBuffer[sample+1] / 32768.0;
-                        maxLeft = Math.Max(maxLeft, sampleLeft);
-                    }
-                    points.Add(new Point(x, maxLeft * 400));
-                    x += 2;
-                }
-
-                // Get Bezier Spline Control Points.
-                Point[] cp1, cp2;
-                BezierSpline.GetCurveControlPoints(points.ToArray(), out cp1, out cp2);
-
-                // Draw curve by Bezier.
-                PathSegmentCollection lines = new PathSegmentCollection();
-                for (int i = 0; i < cp1.Length; ++i)
-                {
-                    lines.Add(new BezierSegment(cp1[i], cp2[i], points[i + 1], true));
-                }
-                PathFigure f = new PathFigure(points[0], lines, false);
-                PathGeometry g = new PathGeometry(new PathFigure[] { f });
-                Path path = new Path() { Stroke = Brushes.Red, StrokeThickness = 1, Data = g, Fill=Brushes.Beige };
-                canvas.Children.Add(path);
-            }
+            var generator = new WaveFormPointsGenerator();
+            var peaks = generator.GetPeaks(@"E:\Audio\Music\Coldplay\X&Y\04-Fix You.mp3", 200);
+            var points = generator.GetPoints(peaks.Select(p => p.LeftMax), 0, 2, 150, -150).ToArray();
+            var geometry = generator.GetBezierPathGeometry(points);
+            Path path = new Path() { Stroke = Brushes.Red, StrokeThickness = 1, Data = geometry, Fill=Brushes.Beige };
+            canvas.Children.Add(path);
         }
 
         /*

File WpfWaveform/WaveFormPointsGenerator.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NAudio.Wave;
+using System.Windows;
+using System.Windows.Media;
+
+namespace WpfWaveform
+{
+    class Peak
+    {
+        public double LeftMin  { get; private set; }
+        public double LeftMax  { get; private set; }
+        public double RightMin { get; private set; }
+        public double RightMax { get; private set; }
+
+        public Peak(double leftMin, double leftMax, double rightMin, double rightMax)
+        {
+            this.LeftMin  = leftMin;
+            this.LeftMax  = leftMax;
+            this.RightMin = rightMin;
+            this.RightMax = rightMax;
+        }
+    }
+
+    class WaveFormPointsGenerator
+    {
+        public IEnumerable<Peak> GetPeaks(string fileName, int millisecondsPerUpdate)
+        {
+            List<Peak> peaks = new List<Peak>();
+            peaks.Add(new Peak(0,0,0,0));
+            using (var reader = new Mp3FileReader(fileName))
+            {
+                int stepSize = (reader.WaveFormat.AverageBytesPerSecond / 1000) * millisecondsPerUpdate;
+                WaveBuffer buffer = new WaveBuffer(stepSize);
+                int read;
+                while ((read = reader.Read(buffer.ByteBuffer, 0, stepSize)) > 0)
+                {
+                    int samples = read / 2; // assume 16 bit
+                    double maxLeft = 0;
+                    double minLeft = 0;
+                    double maxRight = 0;
+                    double minRight = 0;
+                    for (int sample = 0; sample < samples; sample += 2)
+                    {
+                        double sampleLeft = buffer.ShortBuffer[sample] / 32768.0;
+                        maxLeft = Math.Max(maxLeft, sampleLeft);
+                        minLeft = Math.Min(minLeft, sampleLeft);
+                        double sampleRight = buffer.ShortBuffer[sample + 1] / 32768.0;
+                        maxRight = Math.Max(maxRight, sampleLeft);
+                        minRight = Math.Min(minRight, sampleLeft);
+                    }
+                    peaks.Add(new Peak(minLeft, maxLeft, minRight, maxRight));
+                }
+            }
+            peaks.Add(new Peak(0,0,0,0));
+            return peaks;
+        }
+
+        public IEnumerable<Point> GetPoints(IEnumerable<double> magnitude, double xOffset, double xStep, double yOffset, double yMult)
+        {
+            List<Point> points = new List<Point>();
+            foreach (var m in magnitude)
+            {
+                points.Add(new Point(xOffset, yOffset + m * yMult));
+                xOffset += xStep;
+            }
+            return points;
+        }
+
+        public PathGeometry GetBezierPathGeometry(Point[] points)
+        {
+            // Get Bezier Spline Control Points.
+            Point[] cp1, cp2;
+            BezierSpline.GetCurveControlPoints(points, out cp1, out cp2);
+
+            // Draw curve by Bezier.
+            PathSegmentCollection lines = new PathSegmentCollection();
+            for (int i = 0; i < cp1.Length; ++i)
+            {
+                lines.Add(new BezierSegment(cp1[i], cp2[i], points[i + 1], true));
+            }
+            PathFigure f = new PathFigure(points[0], lines, false);
+            PathGeometry g = new PathGeometry(new PathFigure[] { f });
+            return g;
+        }
+    }
+}

File WpfWaveform/WpfWaveform.csproj

       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </ApplicationDefinition>
+    <Compile Include="WaveFormPointsGenerator.cs" />
     <Page Include="MainWindow.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>