WaveView - cut and paste

Jul 9, 2009 at 7:22 PM

I added an OnSizeChange response to Invalidate so the drawing refreshed on a resizeable dialog.

I did a hacky cut and paste which hints at some extra properties I added, but I made it work in terms of file position, not in terms of time which is the way it currently "thinks"..

protected override void OnPaint(PaintEventArgs e)
        {
             if(waveStream != null)
            {
                Pen wave_select = new Pen(select_wave_colour);
                Pen wave = new Pen(wave_colour);
                Pen current_pen;


                if (start_selection >= 0 && end_selection >= 0)
                {
                    long select_start_pos = (start_selection - startPosition) /( bytesPerSample * samplesPerPixel);
                    if (select_start_pos < 0)
                        select_start_pos = 0;
                    long select_end_pos = (end_selection - startPosition) / (bytesPerSample * samplesPerPixel);
                    if (select_end_pos < 0)
                        select_end_pos = 0;
                    Brush select = new SolidBrush(select_colour);
                    int height = Math.Abs(e.ClipRectangle.Bottom - e.ClipRectangle.Top);
                    int width = (int)Math.Abs(select_end_pos - select_start_pos);

                    Rectangle rect = new Rectangle((int)select_start_pos, e.ClipRectangle.Top, width, height);
                    e.Graphics.FillRectangle(select, rect);
                }
                waveStream.Position = 0;
                int bytesRead;
                byte[] waveData = new byte[samplesPerPixel*bytesPerSample];
                waveStream.Position = startPosition + (e.ClipRectangle.Left * bytesPerSample * samplesPerPixel);
                
                for(float x = e.ClipRectangle.X; x < e.ClipRectangle.Right; x+=1)
                {
                    short low = 0;
                    short high = 0;
                    bytesRead = waveStream.Read(waveData, 0, samplesPerPixel * bytesPerSample);
                    if(bytesRead == 0)
                        break;
                    for(int n = 0; n < bytesRead; n+=2)
                    {
                        short sample = BitConverter.ToInt16(waveData, n);
                        if(sample < low) low = sample;
                        if(sample > high) high = sample;
                    }
                    float lowPercent = ((((float) low) - short.MinValue) / ushort.MaxValue);
                    float highPercent = ((((float) high) - short.MinValue) / ushort.MaxValue);
                    if (waveStream.Position >= start_selection &&
                        waveStream.Position <= end_selection)
                        current_pen = wave_select;
                    else
                        current_pen = wave;
                    e.Graphics.DrawLine(current_pen,x,this.Height * lowPercent,x,this.Height * highPercent);                    
                }
                e.Graphics.DrawLine(Pens.DarkMagenta, 0, this.Height / 2, this.Width, this.Height / 2);
            }

            base.OnPaint (e);
        }

 

I think this is where I tripped over the offset stream not being quite right and changed the WaveOffsetStreamto return a fixed length result. (Generally I got a bit baffled between positions and offsets in that code but I changed WaveOffsetStream to use the Length rather than return a full buffer.

public WaveStream SelectedWave
        {
            get
            {
                if (start_selection < 0 || end_selection < 0)
                    return null;
                else
                {
                    WaveOffsetStream temp = new WaveOffsetStream(waveStream);
                    temp.StartPoint = start_selection;
                    temp.SetLength(end_selection - start_selection);
                    return temp;
                }
            }
        }

 

public void FullView()
        {
            if (waveStream == null)
                return;
            start_selection = -1;
            end_selection = -1;
            startPosition = 0;
            
            long end_pos = waveStream.Length ;
            long bytes_shown = end_pos - start_selection;

            samplesPerPixel = (int)bytes_shown / bytesPerSample / Width;
            this.Invalidate();
        }


        public void ZoomToSelection()
        {
            if (waveStream == null)
                return;
            if (start_selection == -1)
                startPosition = 0;
            else
                startPosition = start_selection;
            long end_pos = end_selection == -1 ? waveStream.Length : end_selection;
            long bytes_shown = end_pos - start_selection;
 
            samplesPerPixel = (int)bytes_shown / bytesPerSample / Width;
            this.Invalidate();
        }


        public long PositionFromX(int X)
        {
            long pos;
            if (X >= 0)
                pos = startPosition + X * samplesPerPixel * bytesPerSample;
            else
                pos = startPosition;
            return pos;
        }

 

So there are some coding ideas on how to take it forward. I need to investigate the cut and paste code as it gets some minor errors which get worse.

Response times are good on the display - a 30 minute file is bearable, and if zoomed in, the response is very good.

To do: scrolling the wave display.

 

Spenny

Editor
Jul 9, 2009 at 11:17 PM

Hi Spenny,

I look forwad to trying this out; you wouldn't happen to have a link to a complete example so that I don't have to fiddle with it to much, would you?

Cheers,
OpenSebJ