Page 1 of 5
Draw a waveform with Purebasic and BASS library
Posted: Wed Jun 06, 2018 12:05 pm
by Martin Verlaan
Hi all,
Did anyone ever manage to draw a simple waveform with purebasic using the BASS library? I want to do this with a decoded channel and I know that BASS_ChannelGetLevel or BASS_ChannelGetData can be used for this. I tried some things based on examples I found on internet but so far without succes. Can anyone help me with this? I need it to improve my auto dj software (
https://www.smartmixplayer.com/ )
I have this code now, but it does not generate a waveform
Code: Select all
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
Thanks in advance,
Martin
Re: Draw a waveform with Purebasic and BASS library
Posted: Wed Jun 06, 2018 1:53 pm
by wilbert
I don't have any experience with BASS (and it looks there's no free version ?).
But looking at the documentation, BASS_ChannelGetLevel won't work. The level of a channel is like a VU meter, not a waveform.
So you probably need BASS_ChannelGetData instead.
Re: Draw a waveform with Purebasic and BASS library
Posted: Wed Jun 06, 2018 5:43 pm
by CELTIC88
Re: Draw a waveform with Purebasic and BASS library
Posted: Wed Jun 06, 2018 6:16 pm
by NicTheQuick
Instead of LOWORD and HIWORD you also could use a structre union:
Code: Select all
Structure Channel
left.w
right.w
EndStructure
Structure Sample
StructureUnion
sample.l
channel.Channel
EndStructureUnion
EndStructure
Define sample.Sample
sample\sample = BASS_ChannelGetLevel(channel)
Debug sample\channel\left
Debug sample\channel\right
It is more to write, but maybe you find it interesting.
Re: Draw a waveform with Purebasic and BASS library
Posted: Thu Jun 07, 2018 7:46 am
by Martin Verlaan
wilbert wrote:I don't have any experience with BASS (and it looks there's no free version ?).
But looking at the documentation, BASS_ChannelGetLevel won't work. The level of a channel is like a VU meter, not a waveform.
So you probably need BASS_ChannelGetData instead.
Thanks for this useful tip!
Re: Draw a waveform with Purebasic and BASS library
Posted: Thu Jun 07, 2018 7:54 am
by Martin Verlaan
Thanks, but as far as I can see this is about saving a wave-file, not drawing a waveform
Re: Draw a waveform with Purebasic and BASS library
Posted: Thu Jun 07, 2018 7:56 am
by Martin Verlaan
NicTheQuick wrote:Instead of LOWORD and HIWORD you also could use a structre union:
Very interesting, i prefer this way.
Re: Draw a waveform with Purebasic and BASS library
Posted: Thu Jun 07, 2018 4:16 pm
by CELTIC88
test
Code: Select all
IncludeFile "bass.pbi"
CanvasGadget_width = 800
CanvasGadget_Height = 400
OpenWindow(0, #PB_Ignore, #PB_Ignore, CanvasGadget_width, CanvasGadget_Height, "waveform test", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, CanvasGadget_width, CanvasGadget_Height)
BASS_Init(-1, 44100, 0, 0, #Null)
filename.s = OpenFileRequester("","","*.*",0):If filename ="":End 1:EndIf
channel = BASS_StreamCreateFile(0, @filename,
0, 0, #BASS_STREAM_PRESCAN|#BASS_SAMPLE_FLOAT|#BASS_UNICODE|#BASS_STREAM_DECODE)
#BASS_LEVEL_STEREO = 2
Structure dfloat
ff.f[2]
EndStructure
dfloat.dfloat
BASS_ChannelSetPosition(channel,0,#BASS_POS_BYTE)
len.q = BASS_ChannelGetLength(channel,#BASS_POS_BYTE)
lsec.d = BASS_ChannelBytes2Seconds(channel,len)/CanvasGadget_width; number of seconds by pixel
If lsec > 1.0 : lsec = 1.0 : EndIf
rate = BASS_ChannelSeconds2Bytes(channel,lsec)
nfrm = 1 * len / rate
pix.f = CanvasGadget_width/nfrm
x.f
MaxPixelHeight = CanvasGadget_Height/3
PixelY = CanvasGadget_Height / 2 - MaxPixelHeight
tim = len / 10;BASS_ChannelSeconds2Bytes(channel,60.0)
StartDrawing(CanvasOutput(0))
For i = 0 To nfrm - 1
SetWindowTitle(0, Str(i*100/nfrm) + "%" )
BASS_ChannelGetLevelEx(channel, dfloat, lsec, #BASS_LEVEL_STEREO) ;?#BASS_LEVEL_STEREO
left = dfloat\ff[0]*100.0
right = dfloat\ff[1]*100.0
bp = BASS_ChannelGetPosition(channel,#BASS_POS_BYTE)
If bp - xx >= tim Or xx = 0
DrawText(x, 0, FormatDate("%ii:%ss",BASS_ChannelBytes2Seconds(channel,bp)))
xx =bp
Line(x,0,1,CanvasGadget_Height,$0000FF)
EndIf
Line(x, PixelY+MaxPixelHeight -left*MaxPixelHeight /100, 1, left*MaxPixelHeight /100 , 0)
Line(x, PixelY+MaxPixelHeight, 1, right*MaxPixelHeight /100 ,$C9D63F)
x + pix
Next
Line(0,PixelY+MaxPixelHeight,CanvasGadget_width,1,$0000FF)
StopDrawing()
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Re: Draw a waveform with Purebasic and BASS library
Posted: Thu Jun 07, 2018 7:18 pm
by Martin Verlaan
Awesome CELTIC88, you are the master! Thank you so much for this example! After searching for days on Internet, I am happy to finally see a code that does (almost) what I want, and that I understand.
I'm going to try now to make a real waveform with BASS_ChannelGetData. I need that to get a better view when zooming into the beats of a song.
Re: Draw a waveform with Purebasic and BASS library
Posted: Tue Jun 12, 2018 10:27 am
by Martin Verlaan
Unfortunately I did not succeed to draw a waveform with BASS_ChannelGetData. I'm pretty good in programming but this is just too difficult for me. Can anyone provide an example with BASS_ChannelGetData? I am even willing to pay for it (in that case send me a PM)
Re: Draw a waveform with Purebasic and BASS library
Posted: Tue Jun 12, 2018 3:32 pm
by wilbert
Martin Verlaan wrote:Unfortunately I did not succeed to draw a waveform with BASS_ChannelGetData
How do you want the view to look ?
Do you have any visual example (or screenshot from an audio editor you like) ?
Re: Draw a waveform with Purebasic and BASS library
Posted: Tue Jun 12, 2018 5:07 pm
by jmg49
hi,
perharps this one :
file.s => your file.mp3
MP3D needed but you can easily revert to native code , there were scrolltexts and rasters in this code too
Code: Select all
;credits PureBasic fr for snippets
IncludeFile "fmodex(short).pbi"
Enumeration
#Mainform
#Wave
#spectrum
#win
EndEnumeration
Global fmodsystem.i, Channel.i
i.i
j.i
Max.i
Position.i
YCurrentWave.i
YOldWave.i
EP_InitFXLib()
MP_Graphics3D (1024,768,0,1)
CanvasGadget(#spectrum, 240, 150, 540, 380)
FMOD_System_Create(@fmodsystem)
FMOD_System_Init(fmodsystem, 32, #FMOD_INIT_NORMAL, 0)
File.s = "Gunther.mp3" ; your file
Dim WaveArray.f(1024)
FMOD_System_CreateStream(fmodsystem, @File, #FMOD_SOFTWARE, 0, @sound)
FMOD_System_PlaySound(fmodsystem, #FMOD_CHANNEL_FREE, sound, 0, @channel)
;----MainLoop---------------------------------------------------------------
Repeat
event=WindowEvent()
FMOD_Channel_GetWaveData(Channel, WaveArray(), 1024, 0)
StartDrawing(CanvasOutput(#spectrum))
DrawingMode(#PB_2DDrawing_Transparent)
Box(0, 0, 1026, 500,0)
DrawingMode(#PB_2DDrawing_Default)
For i=1 To 1024
YOldWave=(WaveArray(i-1)+1)*250
YCurrentWave=(WaveArray(i)+1)*250
LineXY(i-1,YOldWave,i,YCurrentWave,RGB(0,200,50))
LineXY(i-1,YOldWave+1,i,YCurrentWave+1,RGB(0,90,50))
LineXY(i-1,YOldWave-1,i,YCurrentWave-1,RGB(0,110,50))
Next
StopDrawing()
MP_RenderWorld()
MP_Flip ()
Until GetAsyncKeyState_(#VK_ESCAPE)
FMOD_Channel_Stop(Channel)
FMOD_System_Release(fmodsystem)
End
Re: Draw a waveform with Purebasic and BASS library
Posted: Tue Jun 12, 2018 7:02 pm
by RASHAD
Consider it as a start
You got the sample data in the buffer now see how you want to draw the curve
Code: Select all
IncludeFile "bass.pbi"
OpenWindow(0, 0,0,800,400, "waveform test", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(0, 10, 10, 780,380)
BASS_Init(-1, 44100, 0, 0, #Null)
filename.s = OpenFileRequester("","","*.*",0):If filename ="":End 1:EndIf
CompilerIf #PB_Compiler_Unicode
*Buffer = Ascii(filename)
sample = BASS_SampleLoad(0, *Buffer, 0, 0, 65535, #BASS_SAMPLE_SOFTWARE)
FreeMemory(*Buffer)
CompilerElse
sample = BASS_SampleLoad(0, @filename, 0, 0, 65535, #BASS_SAMPLE_SOFTWARE)
CompilerEndIf
;To get Channel length in bytes
; # 1 :
; info.BASS_SAMPLE
; BASS_SampleGetInfo(sample, @info)
; channels = info\chans
; length = info\length
; Debug length
; Or
channelh = BASS_SampleGetChannel(sample,1)
length = BASS_ChannelGetLength(channelh,#BASS_POS_BYTE)
;BASS_ChannelPlay(channelh, 0)
*buffer = AllocateMemory(length)
BASS_ChannelGetData(channelh, *buffer, length)
x = 10
For i = 10000 To length-1 Step 3
StartVectorDrawing(CanvasVectorOutput(0))
MovePathCursor(x,350,#PB_Path_Relative)
AddPathCurve(x+2,PeekB(*buffer+i)*10, x+4, PeekB(*buffer+i+1)*10, x+6, PeekB(*buffer+i+2)*10)
VectorSourceColor(RGBA(255, 0, 0, 255))
StrokePath(2)
x + 3
StopVectorDrawing()
Next
Delay(10)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Re: Draw a waveform with Purebasic and BASS library
Posted: Tue Jun 12, 2018 7:37 pm
by CELTIC88
you don't need 'BASS Channel GetData' to zooming in !
in my example you can show 0.001 ms of song
if I have more time I put an example
ps: if your sound is a wav file you can display waveform without (bassapi)
good luck

Re: Draw a waveform with Purebasic and BASS library
Posted: Tue Jun 12, 2018 8:38 pm
by Martin Verlaan
Thanks to all of you for your fast replies and examples!
@Wilbert: I like the view of Cool Edit / Adobe Audition. It doesn’t have to look beautiful with colors and a raster. I just need a simple (but clear) drawing, if possible with 2 channels (stereo)
@jmg49: I’ve modified your code a bit to make it work with BASS. So far, so good, it draws a waveform so I think I can build further on this.
@Rashad: It’s interesting that you use BASS_SampleLoad. I haven’t seen this before in other examples. However, if I run your example it takes about 2 minutes before I see the picture and it doesn’t look good
@CELTIC88: I love your example and I managed to zoom in. But the problem is the zoomed view looks different then a real waveform. It’s not very useful to find a beat. In the pictures (with a zoomed view of 0.029 seconds) below you can see the difference.
Yours:
Cool Edit:
