Author Topic: Draw a waveform  (Read 209 times)

martin71

  • Posts: 23
Draw a waveform
« on: 6 Jun '18 - 12:37 »
Hello everybody,

I want to draw a simple waveform of a  decoded channel in Purebasic.  I know I can use BASS_ChannelGetLevel or BASS_ChannelGetData for this.  I found some examples but still I can not manage to make this. Can someone point me into the right direction?

Code: [Select]
IncludeFile "include/bass.pbi"

Macro LOWORD(a) : ((a)&$FFFF) : EndMacro
Macro HIWORD(a) : (((a)>>16)&$FFFF) : EndMacro

OpenWindow(0, #PB_Ignore, #PB_Ignore, 600, 220, "waveform test", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, 600, 220)


BASS_Init(-1, 44100, 0, 0, #Null)

filename.s = "song.mp3"
channel = BASS_StreamCreateFile(0, @filename, 0, 0, #BASS_STREAM_PRESCAN|#BASS_UNICODE|#BASS_STREAM_DECODE)
 

length = BASS_ChannelBytes2Seconds(channel, #BASS_POS_BYTE)
MaxPixelHeight = 110

x=0
While BASS_ChannelIsActive(channel)
  level = BASS_ChannelGetLevel(channel)
 
  left  = (LOWORD(level) / 3276) * 2                 
  right = (HIWORD(level) / 3276) * 2

  PixelYleft = (MaxPixelHeight / 2) - (left * MaxPixelHeight / 65535)
  PixelYright = (MaxPixelHeight / 2) - (right * MaxPixelHeight / 65535)
 
  If StartDrawing(CanvasOutput(0))
    Line(x, 0, x, PixelYleft , 0)
    Line(x,110, x, PixelYright , 0)   
    StopDrawing()
  EndIf
 
  x+1
Wend

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
« Last Edit: 6 Jun '18 - 12:44 by martin71 »

martin71

  • Posts: 23
Re: Draw a waveform
« Reply #1 on: 7 Jun '18 - 08:04 »
Okay, I understand now that using BASS_ChannelGetLevel is the wrong way. But still I don't know how to do it with BASS_ChannelGetData.

morknotmindy

  • Posts: 11
Re: Draw a waveform
« Reply #2 on: 7 Jun '18 - 10:55 »
If you want to create a static waveform of an mp3 after it has been assigned to your "channel" variable then it is possible to use BASS_ChannelGetLevel to get the necessary data - but I prefer to use BASS_ChannelGetLevelEx. I don't use PureBasic but in Pascal this is how I do it:

Decide how often throughout the mp3 file you want to take a level value, let's say every 0.5 seconds.

Create two open/dynamic array variables (of no fixed length), say leftlevel and rightlevel.

Get the duration of the mp3 in seconds.

Set the dimensions of leftlevel and rightlevel to at least twice the mp3's duration (you're taking values every 0.5 seconds).

Create another array variable, say lvltotal, with a dimension of 2. See BASS_ChannelGetLevelEx documentation.

Create another variable, say counter.

In Pascal the code would then look like this:

counter:=0;

While BASS_ChannelGetLevelEx(channel, @lvltotal,0.5,BASS_LEVEL_STEREO) do
begin
leftlevel[counter]:=lvltotal[1];
rightlevel[counter]:=lvltotal[2];
inc(counter);
end;

You should end up with the two arrays, leftlevel and rightlevel, holding the level values at 0.5 second intervals which you can then plot - bearing in mind that the values will be between 0 and 1 and will probably need multiplying by 100, say.

In Pascal "@lvltotal' is a pointer to the variable.

If you want a dynamic waveform (spectrum??) as the track is playing then I'd have a guess (I don't know how similar PureBasic is to Visual Basic) that the examples provided with BASS in the vb/LiveFX and Spectrum folders will demonstrate BASS_ChannelGetData.

Hope this helps.
« Last Edit: 7 Jun '18 - 11:55 by morknotmindy »

martin71

  • Posts: 23
Re: Draw a waveform
« Reply #3 on: 7 Jun '18 - 19:12 »
Thanks a lot for your explanation morknotmindy! On the Purebasic forum someone provide an example ( https://www.purebasic.fr/english/viewtopic.php?f=13&t=70823&p=523155#p523155 ) that use BASS_ChannelGetLevelEx as well. So with his and your information I can definitely continue with building my code.  ;D

martin71

  • Posts: 23
Re: Draw a waveform
« Reply #4 on: 8 Jun '18 - 20:27 »
My happiness was for a short time. :'(

A waveform generated with the data from BASS_ChannelGetLevelEx looks very good but when you zoom in, it is not as clear as a real waveform generated with PCM data.

I need to zoom in to one hundred seconds to find the exact position of a beat. So I really need BASS_Channelgetdata for this.

The problem is that I just don't understand how to read a decoded channel,  get the right data and how to transform it into a waveform.

I wish I could see a simple example of this in a BASIC language, like VB, powerbasic or whatever (but not .Net). I have seen the LiveSpec example but that one does not use a decoded channel.

@Ian, I have read somewhere that in an old version of BASS an example "simple.bas" was included. Is this example still available somewhere?

martin71

  • Posts: 23
Re: Draw a waveform
« Reply #5 on: 13 Jun '18 - 22:19 »
Members of the Purebasic forum helped me with this. Problem solved,  I can draw a beautiful waveform now.