public async Task LoadFileAsync(string fileName)
        {
            try { audioFile = new BufferedAudioFile(fileName); }
            catch (Exception e)
            {
                System.Windows.MessageBox.Show("Could not load music file: " + Path.GetFileName(fileName) + Environment.NewLine + Environment.NewLine + e.Message, "Problem opening file",
                                               System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
                return;
            }

            MusicFileName = fileName;

            // TODO progress inidicator for file loading
            audioFile.LoadIntoMemoryAsync(null).Forget();
            audioPlayback.Init(audioFile.CreateStream(infinite: true));

            // Initialize our user-facing value from the playback device (which apparently gets its value from Windows).
            MusicVolume = LoudnessHelper.VolumeFromLoudness(audioPlayback.Volume);

            CurrentWaveform = null;
            await RenderWaveformAsync(false);

            Notify(nameof(MusicDuration));
        }
        private void RenderPolygon(DrawingContext drawingContext)
        {
            var fillBrush = Brushes.LawnGreen;
            var borderPen = new Pen(Brushes.DarkGreen, 1.0);

            if (WaveformDisplayMode == WaveformDisplayMode.Linear)
            {
                sampleTransformerFunc = (x => x);
            }
            else if (WaveformDisplayMode == WaveformDisplayMode.Logarithmic)
            {
                sampleTransformerFunc = (x => Math.Sign(x) * LoudnessHelper.VolumeFromLoudness(Math.Abs(x)));
            }
            else
            {
                throw new InvalidOperationException("display mode not supported: " + WaveformDisplayMode);
            }

            var maximums = Waveform.Maximums;
            var minimums = Waveform.Minimums;

            if (maximums.Length == 0)
            {
                return;
            }
            //  px/sample = px/sec    *  sec/sample
            double xScale      = TimeScale * Waveform.TimePerSample;
            double offsetPx    = Waveform.TimeOffset * TimeScale;
            double rightmostPx = offsetPx + maximums.Length * xScale;

            StreamGeometry geometry = new StreamGeometry();

            using (var ctx = geometry.Open())
            {
                ctx.BeginFigure(new Point(offsetPx, SampleToYPosition(maximums[0])), isFilled: true, isClosed: true);

                for (int i = 1; i < maximums.Length; i++)
                {
                    ctx.LineTo(new Point(offsetPx + i * xScale, SampleToYPosition(maximums[i])), true, false);
                }

                ctx.LineTo(new Point(rightmostPx, SampleToYPosition(maximums[maximums.Length - 1])), true, false);
                ctx.LineTo(new Point(rightmostPx, SampleToYPosition(minimums[minimums.Length - 1])), true, false);

                for (int i = minimums.Length - 1; i >= 0; i--)
                {
                    ctx.LineTo(new Point(offsetPx + i * xScale, SampleToYPosition(minimums[i])), true, false);
                }
            }
            geometry.Freeze();

            drawingContext.DrawGeometry(fillBrush, borderPen, geometry);

            // Alternative rendering method that draws rectangles/lines directly onto the drawingContext.

            //for (int i=0; i<maximums.Length; i++)
            //{
            //    double y = SampleToYPosition(maximums[i]);
            //    double h = SampleToYPosition(minimums[i]) - y;
            //    if (h > halfHeight * 0.1 || i == 0)
            //    {
            //        drawingContext.DrawRectangle(fillBrush, null, new Rect(
            //            offsetPx + i * xScale, y,
            //            xScale, h));
            //    } else
            //    {
            //        double prevMid = (SampleToYPosition(maximums[i - 1]) + SampleToYPosition(minimums[i - 1])) / 2;
            //        drawingContext.DrawLine(new Pen(fillBrush, 3),
            //            new Point(offsetPx + (i-1) * xScale, prevMid),
            //            new Point(offsetPx + i * xScale, y + h/2));
            //    }
            //}
        }