Author Topic: WaveForm issues.  (Read 14119 times)

aybe

  • Posts: 145
WaveForm issues.
« on: 4 Apr '10 - 21:28 »
I needed to have a scrolling waveform, so I had a serious look at WaveForm.

  • First issue is that when zooming a lot, the bottom of waves disappears ...
  • Second is performance, that's simply not possible to display on an HD screen, it's too slow.
    A picture of about 1920*256 is too CPU consuming and not smooth at all.
  • Third is, picture flickers ! (you see it a little in the video)

I have created a small code that automatically computes FrameResolution otherwise it was much slower.
For the time being, to have a smooth scrolling I render say a 5000*256 image then shift its Margin (WPF), it eats almost no CPU and is 60fps !

Remove aliasing and playing a bit with colors helps, but picture remains ugly ...

I really wanted to use WaveForm features such as markers but this is blocking.
(I am using last build where rendering performance has increased)

So my question is, is it the best we can get out of WaveForm ?
And, FrameResolution means 1 pixel, right ??

I've created a small video for you to see :

http://rapidshare.com/files/372021682/Untitled.mp4.html

Thank you  ;D

Code: [Select]
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Un4seen.Bass;
using Un4seen.Bass.Misc;

namespace aveform
{
    public partial class Form1 : Form
    {
        private readonly BASSTimer Timer = new BASSTimer();
        private Form2 _form2;
        private int _streamCreateFile;
        private WaveForm _waveForm;

        public Form1()
        {
            InitializeComponent();
            Closing += Form1_Closing;
            Timer.Tick += Timer_Tick;
            SetStyle(ControlStyles.DoubleBuffer |
                     ControlStyles.UserPaint |
                     ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();
        }

        protected int SecondsBefore { get; set; }
        protected int SecondsAfter { get; set; }

        private void Timer_Tick(object sender, EventArgs e)
        {
            /* File durations */
            long length = Bass.BASS_ChannelGetLength(_streamCreateFile, BASSMode.BASS_POS_BYTES);
            double seconds = Bass.BASS_ChannelBytes2Seconds(_streamCreateFile, length);
            /* Current positions */
            long position = Bass.BASS_ChannelGetPosition(_streamCreateFile, BASSMode.BASS_POS_BYTES);
            double second = Bass.BASS_ChannelBytes2Seconds(_streamCreateFile, position);
            /* Drawing bounds */
            double left = second - SecondsBefore;
            double secondsLeft = left < 0 ? 0 : left;
            double right = second + SecondsAfter;
            double secondsRight = right > seconds ? seconds : right;

            /* Resolution */
            long bytesL = Bass.BASS_ChannelSeconds2Bytes(_streamCreateFile, secondsLeft);
            long bytesR = Bass.BASS_ChannelSeconds2Bytes(_streamCreateFile, secondsRight);
            int fL = _waveForm.Position2Frames(bytesL);
            int fR = _waveForm.Position2Frames(bytesR);

            long samples = (bytesR - bytesL)/_waveForm.Wave.bps/8/_waveForm.Wave.chans; /* 16 bits stereo ! */
            double samplesPerPixel = (double) samples/pictureBox1.Width;
            double frameResolution = samplesPerPixel/44100f;
            /* Draw */
            if (_waveForm.IsRendered)
            {
                TimeSpan span = TimeSpan.FromSeconds(second);
                _waveForm.ClearAllMarker();
                _waveForm.AddMarker(string.Format("{0:D2}:{1:D2}", span.Minutes, span.Seconds) + "{Color=Red}", position);
                _waveForm.FrameResolution = frameResolution;
                pictureBox1.Image = _waveForm.CreateBitmap(pictureBox1.Width, pictureBox1.Height, fL, fR, checkBox1.Checked);
                label3.Text = (frameResolution*1000).ToString();
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string mp3 = @"F:\Music\Singles\Videogames\Destruction Derby - One Against All.mp3";

            Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, Handle);
            _streamCreateFile = Bass.BASS_StreamCreateFile(mp3, 0, 0, BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_STREAM_AUTOFREE);
            Bass.BASS_ChannelPlay(_streamCreateFile, false);

            _waveForm = new WaveForm(mp3);
            _waveForm.RenderStart(true, BASSFlag.BASS_DEFAULT);
             _waveForm.DrawMarker = WaveForm.MARKERDRAWTYPE.Line | WaveForm.MARKERDRAWTYPE.Name|WaveForm.MARKERDRAWTYPE.NamePositionMiddle;

          //_waveForm.DrawEnvelope = false;
            //_waveForm.DrawWaveForm = WaveForm.WAVEFORMDRAWTYPE.Mono;
            //_waveForm.DrawGradient = true;
            //_waveForm.ColorBackground = Color.Black;
            //_waveForm.ColorLeft = Color.Red;
            //_waveForm.ColorLeft2 = Color.DarkRed;
            Timer.Interval = (int) numericUpDown1.Value;
            Timer.Start();

            SecondsBefore = (int) numericUpDown2.Value;
            SecondsAfter = (int) numericUpDown3.Value;

            _form2 = new Form2();
            _form2.PropertyGrid.SelectedObject = _waveForm;
            _form2.Show();
        }

        private void Form1_Closing(object sender, CancelEventArgs e)
        {
            _waveForm.RenderStop();
            Timer.Stop();

            bool stop = Bass.BASS_ChannelStop(_streamCreateFile);
            bool free = Bass.BASS_Free();
        }

        private void pictureBox1_SizeChanged(object sender, EventArgs e)
        {
        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            Timer.Interval = (int) numericUpDown1.Value;
        }

        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {
            SecondsBefore = (int) numericUpDown2.Value;
        }

        private void numericUpDown3_ValueChanged(object sender, EventArgs e)
        {
            SecondsAfter = (int) numericUpDown3.Value;
        }
    }
}
« Last Edit: 4 Apr '10 - 21:44 by aybe »

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #1 on: 5 Apr '10 - 07:18 »
FrameResolution is the resolution in milliseconds of one rendered frame (not of 1 pixel).
In the last version the rendering speed was improve, not the drawing speed.

The idea to achive a better performance for a scrolling WaveForm is actually to NOT draw the WaveForm everytime it has to scrolls.
You might for example create a very large WaveForm image and place that on a very large pictureBox.
You can the place this pictureBox into a ScrollingControl and set its AutoScrollPosition when scrolling should happen.

By doing so you would only draw the WaveForm once, but the scroll the pictureBox within the ScrollableControl only.

aybe

  • Posts: 145
Re: WaveForm issues.
« Reply #2 on: 5 Apr '10 - 15:27 »
Hello !

Yes, that's the method I have decided to do,

  • Can you tell why does the waveform gets mangled at very narrow view ?
  • I guess I was wrong in computing FrameResolution, how should I compute FrameResolution then ?

Thank you  :D


radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #3 on: 5 Apr '10 - 18:54 »
You don't 'compute' the FarmeResolution - you specify it before starting the rendering.
E.g. use "0.002", if you want a finer resolution which is presise up to 2 milliseconds.
And what do you mean by "mangled"?

aybe

  • Posts: 145
Re: WaveForm issues.
« Reply #4 on: 6 Apr '10 - 16:49 »
Hi,

Have a look at the video,
When you zoom a lot on the form, the negative amplitudes disappears.

I also tried a manual setting to view the beginning of an audio file (in case my FrameResolution was wrong)
but it does it anyway.



About FrameResolution,

I found out that a large setting provides much less details, (of course)
but doesn't a smaller value than necessary takes more time to draw ?
(e.g. 0.001 for a 5 min. sound which representation would be 100 pixels large)

Actually I'm just trying to understand its purpose as, as you said before,
I'd do my rendering first and not in real-time so it's not performance-related
but trying to understand the internals and use it efficiently.



Thanks for your help ;D

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #5 on: 7 Apr '10 - 18:52 »
Sorry, that it took a bit to fix the zooming issue.
But now the negative amplitudes shouldn't disappear anymore when zooming.

A new version can be obtained here:
  www.un4seen.com/filez/4/Bass24.Net_pre.zip

Or here:
  www.un4seen.com/filez/4/Bass24.Net_update.zip


Regarding the CPU spikes:
You are (re)drawing the whole waveform with every timer tick (e.g. ever 100ms).
So to avoid that you can:
- create a very large picturebox and related image from the WaveForm
- place the large picturebox into a scrollable control (e.g. a panel)
- and further only use the 'AutoScrollPosition' property in your timer tick event to actually scroll the needed portion of the waveform into your view
This would avoid you from calling 'WaveForm.CreateBitmap' with every timer tick

Here are some helps functions which serve you with something to try:
Code: [Select]
// this will e.g. calculate the width of the picturebox for a given track duration and zoom resolution
// e.g.: if the track is 300sec. long and you what a zoom factor, so that one pixel should represent 50ms of the waveform
// then call "int width = PixelFromDuration(300.0, 0.05);"
public int PixelFromDuration(double duration, double resolution)
{
    return (int)Math.Ceiling(duration / resolution);
}

// or the other way around
public double DurationFromPixel(int pixel, double resolution)
{
    return pixel * resolution);
}

// to create your picturebox do something like this:
PictureBox pic = new PictureBox();
pic.Height = 100;
pic.Width = PixelFromDuration(_track.LenghtSec, 0.05);
// now draw the whole waveform to this picturebox
pic.BackgroundImage = _waveForm.CreateBitmap(pic.Width, pic.Height, -1, -1, true);

// now you can add this picturebox to a fixed size Panel control
// use the AutoScrollPosition property of the panel to adjust the position of the picturebox within the panel

aybe

  • Posts: 145
Re: WaveForm issues.
« Reply #6 on: 8 Apr '10 - 01:04 »
No that's fine,

Excellent,

I don't know why but Forms performance is disastrous (30% CPU), WPF is almost 0% !
Probably it's hardware-accelerated ...

thank you  ;D

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #7 on: 9 Apr '10 - 10:55 »
Hello,
i have a question about the scrolling waveform, i try to do it but i didnīt.
can you may be give me a help?

thx

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #8 on: 9 Apr '10 - 11:40 »
Can you explain a bit further what "it didn't"?
And may be show some of your code to see what you tried?

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #9 on: 9 Apr '10 - 11:54 »
hmm i try to put a picturebox in a WindowsscrollBar,
how i have to to the Autoscrolling ?
i try what you explain in the topic before.

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #10 on: 9 Apr '10 - 12:13 »
Can you explain a bit further what "it didn't"?
And may be show some of your code to see what you tried?
Code: [Select]
private void DrawWavePosition(long pos, long len)
{
// Note: we might take the latency of the device into account here!
// so we show the position as heard, not played.
// That's why we called Bass.Bass_Init with the BASS_DEVICE_LATENCY flag
// and then used the BASS_INFO structure to get the latency of the device

if (len == 0 || pos < 0)
{
this.pictureBox1.Image = null;
return;
}

Bitmap bitmap = null;
Graphics g = null;
Pen p = null;
double bpp = 0;

try
{
if (_zoomed)
{
// total length doesn't have to be _zoomDistance sec. here
len = WF.Frame2Bytes(_zoomEnd) - _zoomStartBytes;

                   
int scrollOffset = 1;
// if we scroll out the window...(scrollOffset*20ms before the zoom window ends)
if ( pos > (_zoomStartBytes + len - scrollOffset*WF.Wave.bpf) )
{
// we 'scroll' our zoom with a little offset
_zoomStart = WF.Position2Frames(pos - scrollOffset*WF.Wave.bpf);
_zoomStartBytes = WF.Frame2Bytes(_zoomStart);
_zoomEnd = _zoomStart + WF.Position2Frames( _zoomDistance ) - 1;
if (_zoomEnd >= WF.Wave.data.Length)
{
// beyond the end, so we zoom from end - _zoomDistance.
_zoomEnd = WF.Wave.data.Length-1;
_zoomStart = _zoomEnd - WF.Position2Frames( _zoomDistance ) + 1;
if (_zoomStart < 0)
_zoomStart = 0;
_zoomStartBytes = WF.Frame2Bytes(_zoomStart);
// total length doesn't have to be _zoomDistance sec. here
len = WF.Frame2Bytes(_zoomEnd) - _zoomStartBytes;
}
// get the new wave image for the new zoom window
DrawWave();
}
// zoomed: starts with _zoomStartBytes and is _zoomDistance long
pos -= _zoomStartBytes; // offset of the zoomed window

bpp = len/(double)this.pictureBox1.Width;  // bytes per pixel
}
else
{
// not zoomed: width = length of stream
bpp = len/(double)this.pictureBox1.Width;  // bytes per pixel
}

// we take the device latency into account
// Not really needed, but if you have a real slow device, you might need the next line
// so the BASS_ChannelGetPosition might return a position ahead of what we hear
pos -= _deviceLatencyBytes;

p = new Pen(Color.Red);
bitmap = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height);
g = Graphics.FromImage(bitmap);
g.Clear( Color.White );
int x = (int)Math.Round(pos/bpp);  // position (x) where to draw the line
g.DrawLine( p, x, 0, x,  this.pictureBox1.Height-1);
bitmap.MakeTransparent( Color.White );
}
catch
{
bitmap = null;
}
finally
{
// clean up graphics resources
if (p != null)
p.Dispose();
if (g != null)
g.Dispose();
}

this.pictureBox1.Image = bitmap;
}

private void buttonZoom_Click(object sender, System.EventArgs e)
{
if (WF == null)
return;

// WF is not null, so the stream must be playing...
if (_zoomed)
{
// unzoom...(display the whole wave form)
_zoomStart = -1;
_zoomStartBytes = -1;
_zoomEnd = -1;
_zoomDistance = 2.0f; // zoom = 5sec.
}
else
{
// zoom...(display only a partial wave form)
long pos = Bass.BASS_ChannelGetPosition(this._stream);
// calculate the window to display
_zoomStart = WF.Position2Frames(pos);
_zoomStartBytes = WF.Frame2Bytes(_zoomStart);
_zoomEnd = _zoomStart + WF.Position2Frames( _zoomDistance ) - 1;
if (_zoomEnd >= WF.Wave.data.Length)
{
// beyond the end, so we zoom from end - _zoomDistance.
_zoomEnd = WF.Wave.data.Length-1;
_zoomStart = _zoomEnd - WF.Position2Frames( _zoomDistance ) + 1;
_zoomStartBytes = WF.Frame2Bytes(_zoomStart);
}
}
_zoomed = !_zoomed;
// and display this new wave form
DrawWave();
}

from the Simple Sample
i jsut whant to scroll with a scrollBar

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #11 on: 9 Apr '10 - 13:03 »
This code hasn't anything to do with placing a picturebox into a scrollable control?!

You mentioned, that you try to place a picturebox into a scrollbar?
You can not assign a picturebox as a child control to a scrollbar.
You need to use a scrollable control, e.g. a panel control.
Using the "AutoScrollPosition" property of a scrollable control is explained in the .Net help (e.g. look to the MSDN).
I guess this has nothing to do with BASS or Bass.Net?

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #12 on: 9 Apr '10 - 14:00 »
i understand what you mind,
my question how can i scroll throw the Waveform?
i click the zoom button and whant to use the scrollbar Control,
sorry when i already ask about the problem  :(

Thank you for the help

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #13 on: 9 Apr '10 - 15:27 »
You can not directly scroll through a WaveForm - you need to (re)draw it (assuming its current view doen't fit into your picturebox).
When drawing a WaveForm you can specify a 'frameStart' and 'frameEnd' index.
So if you want to 'scroll' it, you need to redraw it with the appropriate 'frameStart' and 'frameEnd' parameters - just like shown in the first post here.

But to avoid redrawing, my advice was to use a 'scrollable' control - see the .Net help for more info - as described above.

aybe

  • Posts: 145
Re: WaveForm issues.
« Reply #14 on: 9 Apr '10 - 15:43 »
Hi,

For Forms :

- Add a Panel to your Form, set Anchor to Top,Left,Bottom,Right so when you resize your Form, it will too
- Inside that Panel, add your PictureBox in which you will switch to AutoSize mode, extremely important ! (Ensures to have the good size)
- Now set Panel's AutoScroll to true.

You can already check the result by running your thing;

Now you can do what radio42 said, AutoScrollPosition  ;D

aybe

  • Posts: 145
Re: WaveForm issues.
« Reply #15 on: 9 Apr '10 - 16:16 »
Hello Aybe,
i lies your post about my question.
what i whant to now is, i use the TESTDSP sample from BAss und i just whant to zoom in and out. but when i zoom in i whant to use the scrollbar control.
Thx for the help

Post your questions in the thread !


Why don't you try both code samples we have put on that thread ??
Mine offers some sort of zooming, radio42's code helps further in getting a specific image size.

You might want to look at how SoundForge or Wavelab does that, for instance ...

As radio42 said, you are better off generating a large image first,
in your case you'd want to generate multiple images but this is not the best since you
may want to zoom to different levels ...

This is my implementation of what said radio42 :

Code: [Select]
private const double _frameResolution = 0.01;
long duration = Bass.BASS_ChannelGetLength(_streamCreateFile);
double seconds = Bass.BASS_ChannelBytes2Seconds(_streamCreateFile, duration);
_widthFromDuration = WidthFromDuration(seconds, _frameResolution);
Bitmap bitmap = _waveForm.CreateBitmap((int) _widthFromDuration, 256, -1, -1, checkBox1.Checked);
           
 private void Timer_Tick(object sender, EventArgs e)
        {
            /* File durations */
            long length = Bass.BASS_ChannelGetLength(_streamCreateFile, BASSMode.BASS_POS_BYTES);
            double seconds = Bass.BASS_ChannelBytes2Seconds(_streamCreateFile, length);
            /* Current positions */
            long position = Bass.BASS_ChannelGetPosition(_streamCreateFile, BASSMode.BASS_POS_BYTES);
            double second = Bass.BASS_ChannelBytes2Seconds(_streamCreateFile, position);
            double duration = WidthFromDuration(second, _frameResolution);
            /* Scroll ! */
            panel1.AutoScrollPosition = new Point((int) duration, 0);
        }

        public double WidthFromDuration(double duration, double resolution)
        {
            double ceiling = Math.Ceiling(duration/resolution);
            return ceiling;
        }

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #16 on: 16 Apr '10 - 07:18 »
hello aybe,

when i understand what you mind, i donīt need to use the Timerupdate_Tick from TestDsp sample,
i have to rewrite it like you post on the code? im embarassed how i have to realise it?

Thank you for the help

aybe

  • Posts: 145
Re: WaveForm issues.
« Reply #17 on: 16 Apr '10 - 17:01 »
hi,

I think it's the best, you could use a delegate (maybe) but why ?
Just don't draw from your callback, as it needs to be fast (callback) and display would freeze as it's called too fast for drawing.


Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #18 on: 22 Apr '10 - 09:27 »
hmm,
what i try to do is to draw the waveform  and when the waveform is to small in the picturebox,
zoom in und scroll to the horizontal like in that audacity program.
I need your Help.

Thank you

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #19 on: 30 Apr '10 - 09:08 »
a) have you tried the above samples?
b) if yes, what is not working with them?
c) have you also took a look to the C# sample called "Simple" - this one actually implements something very close to what you are asking for
    You can double-click on the waveform to zoom-in and once the current-position runs out of visibility, the waveform is scrolled horizontally

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #20 on: 30 Apr '10 - 09:15 »
her is my code in the rar file i make a panel  and try to draw the Wave in the panel
see the class Timer_updatetrick.

Thank you
« Last Edit: 30 Apr '10 - 09:24 by Pmbasso »

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #21 on: 30 Apr '10 - 10:27 »
You seem to have modified quite some things, which aren't correct.
When you look at the "DrawWave()" method, you will see, that the waveform is actually drawn to the pictureBox1 control.
But you have hidden that control.
So open the designer and bring the pictureBox1 control to the top - so that it is actually visible.
Then all should work.
Click on "Zoom In" and you'll see, that the position is 'scrolling'.

If that is not what you want - then you can use the methods as posted here on the thread (above) to use a panel and place the pictureBox INSIDE that panel.

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #22 on: 30 Apr '10 - 10:40 »
i actually try the code, but i have a question by this one

pic.Height = 100;
                    pic.Width = PixelFromDuration(_track.LengthSec, 0.05);
                    pic.BackgroundImage = WF.CreateBitmap(pic.Width, pic.Height, -1, -1, true);

what are you mean with "_track.LengthSec" ?

can i use the picturebox1 and add it to the panel ?
and what i think i have to draw the waveform after i click the openfiledialog, before i play the file
hmm i try it and give you after a feedback.
sorry with my englisch  ;).
i give my best  :)

radio42

  • Posts: 4576
Re: WaveForm issues.
« Reply #23 on: 30 Apr '10 - 11:36 »
Yes, a panel control is a ScrollableControl and can contain any number of child controls.
"_track.LengthSec" was just a hint and should represent the length of a track in seconds.

So before playing too much with the WaveForm I guess you should try the following upfront (without any BASS stuff in it):
a) create a new and empty windows form
b) place a panel control onto that form (set the 'Size.Width' of that panel to e.g. 350)
c) place a picturebox control inside that panel control
d) set the panel controls 'AutoScroll' property to TRUE (e.g. in the designer properties)
e) now set the 'Size.Width' property of the picturebox control to something big (e.g. 3000)

Now assume/imagine the follwing:
- your picturebox control will represent your waveform
- the width of the picturebox needs to be calculated according to the length of the audio file
- but before doing that just assume this is already done and the width here is 10000 pixel
- e.g. one pixel will represent 100 milliseconds of the audio
- as such in this simple example the length of the audio would be 3000 x 100ms = 300000ms = 300sec. = 5min.

So now you have the following situation:
- the pixturebox width is bigger than the panel control it is contained in
- the picturebox will represent the whole waveform given a fixed zomm factor (in the above example 100ms per pixel)
- but the panel control has only a width of 350 pixel
- this means, that the picturebox is only displayed partially
- the panel is able to display 350 x 100ms = 35000ms = 35sec.

So now you can use the "AutoScrollPosition" property of the panel control to bring a certain part of the picturebox in view.
The panel control can as such 'scroll' the picturebox and bring the relevant part into view.

You should first play around with this in a new and empty windows form to learn how this actually works.
This has nothing to do with BASS/BASS.NET - it is pure .Net stuff.

Now when you know all that, then you can start thinking about how you could use this for the scrolling WaveForm.

E.g. you have your panel control with the contained picturebox etc.
So when you now create a stream with BASS you can get the length of the audio file (via BASS_ChannelGetLength and BASS_ChannelBytes2Seconds).
Lets assume the length of the audio file is 321 seconds long.
You can now calculate the actual length of the picturebox for a given zoom factor (e.g. 100ms per pixel).
width = (321*1000)/100 = 3210 pixel   (width = (lengthsec*1000)/zoom)

Now you can set the picturebox width programmatically at runtime.
And render the WHOLE waveform to the picturebox - like in the examples (using -1 and -1 for the start/end parameter).
This means you only draw the WaveForm ONCE! There is no need to draw it in any timer event.
But in the timer event you can now set the "AutoScrollPosition" property of the panel control to 'scroll' the picturebox to bring the current part into view.

Pmbasso

  • Posts: 51
Re: WaveForm issues.
« Reply #24 on: 7 May '10 - 07:49 »
I make it like you explain but i already have a problem when i draw the waveform  :'(,
and i have to resolve this problem. radio42 can you may be give me a example with the code i post before?

Thank you