2

I am currently building a Waveform Control in WPF. I am planing to build a zoom feature. That means the user should have to ability to see every single sample of the whole audio file. As everyone knows... and audiofile can have very very very many samples. So I would have to draw extremly many lines and that would be overhead.

So I thought about drawing the lines only when they are requested. The problem is that I have no idea what would be the best and CLEANEST way to do that. Do you have any ideas how I could start building such a feature. I don't want a code looking like a fried brain. I would be very thankfull if somebody would have a nice idea to start solving that problem.

JosephGarrone
  • 4,081
  • 3
  • 38
  • 61
Florian
  • 5,918
  • 3
  • 47
  • 86

1 Answers1

0

A way to achieve that could be obtaining the visible range of the track, then draw lines belonging to that region. This control could be helpful to you. Personally, even if it wouldn't use WPF's zooming features, I'd keep the samples' coordinates in a readonly collection, then multiply their components by the zoom factor when a rendering is demanded. You would have a ScrollViewer with ScrollableWidth (assuming that your samples spans horizontally) equals to the last sample's multiplied x coordinate. One way to obtain the above effect would be always drawing the last sample, without connecting it to the last visible one. Finally, you would draw the visible lines in a container of your choice and use it for the ScrollViewer's Content property.

Adding a small example using a Canvas and a ScrollViewer, you can use it to update the content upon scrolling/zooming.

var scrollViewer = _scrollViewer; //_scrollViewer is our container
var min = scrollViewer.ContentHorizontalOffset; //Calculating visible ranges
var max = min + scrollViewer.ViewportWidth;
int[] samples = { 10, 20, 30, 50, 80, 90, 100, 130 }; //Our original samples
const double zoomFactor = 10.0;
var canvas = new Canvas {HorizontalAlignment = HorizontalAlignment.Left};
foreach (var sampleX in samples)
{
    var multipliedX = sampleX*zoomFactor;
    if (multipliedX < min || multipliedX > max) continue;
    var sampleCircle = new Ellipse {Width = 5, Height = 5, Stroke = Brushes.Black}; //Our Shape for the sample
    canvas.Children.Add(sampleCircle);
    Canvas.SetLeft(sampleCircle, multipliedX);
}
canvas.Width = samples.Last()*zoomFactor; //To extend the ScrollViewer's scrollable width
scrollViewer.Content = canvas;
e_ne
  • 8,340
  • 32
  • 43