Draw a waveform with Purebasic and BASS library
Re: Draw a waveform with Purebasic and BASS library
Hi Martin
The data are the curve peaks
Search the forum for how to draw Spline between points
Good luck
The data are the curve peaks
Search the forum for how to draw Spline between points
Good luck
Egypt my love
Re: Draw a waveform with Purebasic and BASS library
Here's a very simple example just to show how you can draw the wave from sample data.
It does no checks at all at the moment so it assumes the audio is 16 bit stereo, it assumes there's enough memory to load the entire song and it assumes the song is long enough to fill the entire width of the CanvasGadget.
The idea is simply to get the min and max values of a number of samples and use those values to connect the dots.
It does no checks at all at the moment so it assumes the audio is 16 bit stereo, it assumes there's enough memory to load the entire song and it assumes the song is long enough to fill the entire width of the CanvasGadget.
The idea is simply to get the min and max values of a number of samples and use those values to connect the dots.
Code: Select all
Structure Sample
l.w
r.w
EndStructure
BASS_Init(-1, 44100, 0, 0, #Null)
Channel.l = BASS_StreamCreateFile(#False, @"Test.mp3", 0, 0, #BASS_STREAM_PRESCAN|#BASS_STREAM_DECODE|#BASS_UNICODE)
Length.q = BASS_ChannelGetLength(Channel, #BASS_POS_BYTE)
SamplesPerPoint = 8
Dim Buffer.Sample(Length >> 2)
BASS_ChannelGetData(Channel, @Buffer(), Length)
OpenWindow(0, 0, 0, 620, 320, "Waveform", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 10, 10, 600, 300)
StartDrawing(CanvasOutput(0))
Box(0, 0, 600, 300, $e0e0e0)
PrevMinL.w = 0 : PrevMaxL.w = 0
PrevMinR.w = 0 : PrevMaxR.w = 0
For i = 0 To 599
MinL.w = Buffer(i*SamplesPerPoint)\l : MaxL.w = MinL
MinR.w = Buffer(i*SamplesPerPoint)\r : MaxR.w = MinR
j = 1
While j < SamplesPerPoint
If Buffer(i*SamplesPerPoint + j)\l < MinL : MinL = Buffer(i*SamplesPerPoint + j)\l : EndIf
If Buffer(i*SamplesPerPoint + j)\l > MaxL : MaxL = Buffer(i*SamplesPerPoint + j)\l : EndIf
If Buffer(i*SamplesPerPoint + j)\r < MinR : MinR = Buffer(i*SamplesPerPoint + j)\r : EndIf
If Buffer(i*SamplesPerPoint + j)\r > MaxR : MaxR = Buffer(i*SamplesPerPoint + j)\r : EndIf
j + 1
Wend
If PrevMinL > MaxL : LineXY(i, 75 - PrevMinL>>9, i, 75 - MaxL>>9, $ff8000) : EndIf
If PrevMaxL < MinL : LineXY(i, 75 - PrevMaxL>>9, i, 75 - MinL>>9, $ff8000) : EndIf
If PrevMinR > MaxR : LineXY(i, 225 - PrevMinR>>9, i, 225 - MaxR>>9, $ff8000) : EndIf
If PrevMaxR < MinR : LineXY(i, 225 - PrevMaxR>>9, i, 225 - MinR>>9, $ff8000) : EndIf
LineXY(i, 75 - MinL>>9, i, 75 - MaxL>>9, $ff8000)
LineXY(i, 225 - MinR>>9, i, 225 - MaxR>>9, $ff8000)
PrevMinL = MinL : PrevMaxL = MaxL
PrevMinR = MinR : PrevMaxR = MaxR
Next
StopDrawing()
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
-
- Enthusiast
- Posts: 124
- Joined: Sun Apr 01, 2018 11:26 am
Re: Draw a waveform with Purebasic and BASS library
Hi Wilbert,
Whoohoo, this is what I need! If I run your example I see a zoomed view. I noticed that I can change the length of the waveform with SamplesPerPoint. What formula should I use to show the complete song as a waveform? And how can I zoom in to a specific start position and length?
It's cool to see that more people here working with the BASS Library. I am curious what kind of audio software has been made by Purebasic developers.
Whoohoo, this is what I need! If I run your example I see a zoomed view. I noticed that I can change the length of the waveform with SamplesPerPoint. What formula should I use to show the complete song as a waveform? And how can I zoom in to a specific start position and length?
It's cool to see that more people here working with the BASS Library. I am curious what kind of audio software has been made by Purebasic developers.
wilbert wrote:Here's a very simple example just to show how you can draw the wave from sample data.
It does no checks at all at the moment so it assumes the audio is 16 bit stereo, it assumes there's enough memory to load the entire song and it assumes the song is long enough to fill the entire width of the CanvasGadget.
The idea is simply to get the min and max values of a number of samples and use those values to connect the dots.
Code: Select all
Structure Sample l.w r.w EndStructure BASS_Init(-1, 44100, 0, 0, #Null) Channel.l = BASS_StreamCreateFile(#False, @"Test.mp3", 0, 0, #BASS_STREAM_PRESCAN|#BASS_STREAM_DECODE|#BASS_UNICODE) Length.q = BASS_ChannelGetLength(Channel, #BASS_POS_BYTE) SamplesPerPoint = 8 Dim Buffer.Sample(Length >> 2) BASS_ChannelGetData(Channel, @Buffer(), Length) OpenWindow(0, 0, 0, 620, 320, "Waveform", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) CanvasGadget(0, 10, 10, 600, 300) StartDrawing(CanvasOutput(0)) Box(0, 0, 600, 300, $e0e0e0) PrevMinL.w = 0 : PrevMaxL.w = 0 PrevMinR.w = 0 : PrevMaxR.w = 0 For i = 0 To 599 MinL.w = Buffer(i*SamplesPerPoint)\l : MaxL.w = MinL MinR.w = Buffer(i*SamplesPerPoint)\r : MaxR.w = MinR j = 1 While j < SamplesPerPoint If Buffer(i*SamplesPerPoint + j)\l < MinL : MinL = Buffer(i*SamplesPerPoint + j)\l : EndIf If Buffer(i*SamplesPerPoint + j)\l > MaxL : MaxL = Buffer(i*SamplesPerPoint + j)\l : EndIf If Buffer(i*SamplesPerPoint + j)\r < MinR : MinR = Buffer(i*SamplesPerPoint + j)\r : EndIf If Buffer(i*SamplesPerPoint + j)\r > MaxR : MaxR = Buffer(i*SamplesPerPoint + j)\r : EndIf j + 1 Wend If PrevMinL > MaxL : LineXY(i, 75 - PrevMinL>>9, i, 75 - MaxL>>9, $ff8000) : EndIf If PrevMaxL < MinL : LineXY(i, 75 - PrevMaxL>>9, i, 75 - MinL>>9, $ff8000) : EndIf If PrevMinR > MaxR : LineXY(i, 225 - PrevMinR>>9, i, 225 - MaxR>>9, $ff8000) : EndIf If PrevMaxR < MinR : LineXY(i, 225 - PrevMaxR>>9, i, 225 - MinR>>9, $ff8000) : EndIf LineXY(i, 75 - MinL>>9, i, 75 - MaxL>>9, $ff8000) LineXY(i, 225 - MinR>>9, i, 225 - MaxR>>9, $ff8000) PrevMinL = MinL : PrevMaxL = MaxL PrevMinR = MinR : PrevMaxR = MaxR Next StopDrawing() Repeat Event = WaitWindowEvent() Until Event = #PB_Event_CloseWindow
Re: Draw a waveform with Purebasic and BASS library
You can try something like thisMartin Verlaan wrote:Whoohoo, this is what I need! If I run your example I see a zoomed view. I noticed that I can change the length of the waveform with SamplesPerPoint. What formula should I use to show the complete song as a waveform? And how can I zoom in to a specific start position and length?
Code: Select all
Structure Sample
l.w
r.w
EndStructure
Procedure UpdateWaveImage(PBImage, *SampleData.Sample, SampleCount)
Protected.i Width, Height, X, VOffsetL, VOffsetR, Mul
Protected.i SamplesPerPixel, Sample
Protected.w MinL, MaxL, MinR, MaxR
Protected.w MinL_, MaxL_, MinR_, MaxR_
If *SampleData And SampleCount
StartDrawing(ImageOutput(PBImage))
Width = OutputWidth() : Height = OutputHeight()
VOffsetL = Height >> 2 : VOffsetR = VOffsetL + Height >> 1
Mul = (VOffsetL * $19999) >> 16
Box(0, 0, Width, Height, $ffe0e0e0)
Line(0, VOffsetL, Width, 1, $ffa0a0a0)
Line(0, VOffsetR, Width, 1, $ffa0a0a0)
SamplesPerPixel = (SampleCount + Width - 1) / Width
MinL = $7fff : MaxL = $8000 : MinR = $7fff : MaxR = $8000
MinL_ = $8000 : MaxL_ = $7fff : MinR_ = $8000 : MaxR_ = $7fff
While SampleCount
If *SampleData\l < MinL : MinL = *SampleData\l : ElseIf *SampleData\l > MaxL : MaxL = *SampleData\l : EndIf
If *SampleData\r < MinR : MinR = *SampleData\r : ElseIf *SampleData\r > MaxR : MaxR = *SampleData\r : EndIf
*SampleData + 4
Sample + 1 : SampleCount - 1
If Sample = SamplesPerPixel Or SampleCount = 0
MinL = (MinL * Mul) >> 16 : MaxL = (MaxL * Mul) >> 16
MinR = (MinR * Mul) >> 16 : MaxR = (MaxR * Mul) >> 16
If MinL_ > MaxL : LineXY(X, VOffsetL - MinL_, X, VOffsetL - MaxL, $ffff8000) : EndIf
If MaxL_ < MinL : LineXY(X, VOffsetL - MaxL_, X, VOffsetL - MinL, $ffff8000) : EndIf
If MinR_ > MaxR : LineXY(X, VOffsetR - MinR_, X, VOffsetR - MaxR, $ffff8000) : EndIf
If MaxR_ < MinR : LineXY(X, VOffsetR - MaxR_, X, VOffsetR - MinR, $ffff8000) : EndIf
LineXY(X, VOffsetL - MinL, X, VOffsetL - MaxL, $ffff8000)
LineXY(X, VOffsetR - MinR, X, VOffsetR - MaxR, $ffff8000)
MinL_ = MinL : MaxL_ = MaxL : MinR_ = MinR : MaxR_ = MaxR
MinL = $7fff : MaxL = $8000 : MinR = $7fff : MaxR = $8000
X + 1 : Sample = 0
EndIf
Wend
StopDrawing()
EndIf
EndProcedure
BASS_Init(-1, 44100, 0, 0, #Null)
Channel.l = BASS_StreamCreateFile(#False, @"Test.mp3", 0, 0, #BASS_STREAM_PRESCAN|#BASS_STREAM_DECODE|#BASS_UNICODE)
Length.q = BASS_ChannelGetLength(Channel, #BASS_POS_BYTE)
Dim Buffer.Sample(Length >> 2)
BASS_ChannelGetData(Channel, @Buffer(), Length)
OpenWindow(0, 0, 0, 620, 320, "Waveform", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
WaveImage = CreateImage(#PB_Any, 8192, 256)
UpdateWaveImage(WaveImage, @Buffer(), Length >> 2)
ScrollAreaGadget(0, 10, 10, 600, 300, ImageWidth(WaveImage), ImageHeight(WaveImage), 10, #PB_ScrollArea_Center)
ImageGadget(1, 0, 0, 600, 300, ImageID(WaveImage))
CloseGadgetList()
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
It could be made much faster using asm but not everyone likes that. So far it's PB code only.
By Creating a different size image, or altering the starting point and sample count for the UpdateWaveImage procedure, you can change the output.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
-
- Enthusiast
- Posts: 124
- Joined: Sun Apr 01, 2018 11:26 am
Re: Draw a waveform with Purebasic and BASS library
Thanks a lot for your help Wilbert
Re: Draw a waveform with Purebasic and BASS library
thank you DR @wilbert,
very good code .
But the picture of waveform appears wrong
very good code .
But the picture of waveform appears wrong
interested in Cybersecurity..
Re: Draw a waveform with Purebasic and BASS library
Hi CELTIC88
Can you post the name of the sound file you been testing?
Can you post the name of the sound file you been testing?
Egypt my love
Re: Draw a waveform with Purebasic and BASS library
hi @RASHAD
Egypt lost vs Uruguay , good luck in next match
https://a.uguu.se/k8ErarzJCDUZ_notify.wav
Egypt lost vs Uruguay , good luck in next match
https://a.uguu.se/k8ErarzJCDUZ_notify.wav
interested in Cybersecurity..
Re: Draw a waveform with Purebasic and BASS library
The problem is that it's a mono file while my code is expecting a stereo file.CELTIC88 wrote:https://a.uguu.se/k8ErarzJCDUZ_notify.wav
I'm not very familiar with BASS. It would be nice if there would be an option that converts mono automatically to two channels so it reads as stereo but I don't know if BASS offers that.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Draw a waveform with Purebasic and BASS library
AH OK
you can use "BASS_ChannelGetInfo" to detect number of channel ?
you can use "BASS_ChannelGetInfo" to detect number of channel ?
interested in Cybersecurity..
-
- Enthusiast
- Posts: 124
- Joined: Sun Apr 01, 2018 11:26 am
Re: Draw a waveform with Purebasic and BASS library
Code: Select all
Define Info.BASS_CHANNELINFO
Bass_ChannelGetInfo(Channel, @Info)
Debug Info\chans ; 1=mono, 2=stereo, etc.
-
- Enthusiast
- Posts: 124
- Joined: Sun Apr 01, 2018 11:26 am
Re: Draw a waveform with Purebasic and BASS library
I'm not sure what is causing it.Martin Verlaan wrote:@Wilbert, your code works great but when I zoom in a lot, the waveform looks distorted. It happens with all my files. Any idea what could be the reason of this? This is a view of 0.145 seconds
You could try to remove the lines below and see what is happening then.
Code: Select all
If MinL_ > MaxL : LineXY(X, VOffsetL - MinL_, X, VOffsetL - MaxL, $ffff8000) : EndIf
If MaxL_ < MinL : LineXY(X, VOffsetL - MaxL_, X, VOffsetL - MinL, $ffff8000) : EndIf
If MinR_ > MaxR : LineXY(X, VOffsetR - MinR_, X, VOffsetR - MaxR, $ffff8000) : EndIf
If MaxR_ < MinR : LineXY(X, VOffsetR - MaxR_, X, VOffsetR - MinR, $ffff8000) : EndIf
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
-
- Enthusiast
- Posts: 124
- Joined: Sun Apr 01, 2018 11:26 am
Re: Draw a waveform with Purebasic and BASS library
Unfortunately that does not help. Maybe it's a limitation or BASS, I will ask on the BASS forum.
Re: Draw a waveform with Purebasic and BASS library
Can you try with this updated procedure ?Martin Verlaan wrote:Unfortunately that does not help. Maybe it's a limitation or BASS, I will ask on the BASS forum.
Code: Select all
Procedure UpdateWaveImage(PBImage, *SampleData.Sample, SampleCount)
Protected.i Width, Height, X, VOffsetL, VOffsetR, Mul
Protected.i SamplesPerPixel, Sample
Protected.w MinL, MaxL, MinR, MaxR
If *SampleData And SampleCount
StartDrawing(ImageOutput(PBImage))
Width = OutputWidth() : Height = OutputHeight()
VOffsetL = Height >> 2 : VOffsetR = VOffsetL + Height >> 1
Mul = (VOffsetL * $19999) >> 16
Box(0, 0, Width, Height, $ffe0e0e0)
Line(0, VOffsetL, Width, 1, $ffa0a0a0)
Line(0, VOffsetR, Width, 1, $ffa0a0a0)
SamplesPerPixel = (SampleCount + Width - 1) / Width
If SampleCount
MinL = *SampleData\l : MinR = *SampleData\r : MaxL = MinL : MaxR = MinR
While SampleCount
If *SampleData\l < MinL : MinL = *SampleData\l : ElseIf *SampleData\l > MaxL : MaxL = *SampleData\l : EndIf
If *SampleData\r < MinR : MinR = *SampleData\r : ElseIf *SampleData\r > MaxR : MaxR = *SampleData\r : EndIf
Sample + 1 : SampleCount - 1
If Sample = SamplesPerPixel Or SampleCount = 0
MinL = (MinL * Mul) >> 16 : MaxL = (MaxL * Mul) >> 16
MinR = (MinR * Mul) >> 16 : MaxR = (MaxR * Mul) >> 16
LineXY(X, VOffsetL - MinL, X, VOffsetL - MaxL, $ffff8000)
LineXY(X, VOffsetR - MinR, X, VOffsetR - MaxR, $ffff8000)
MinL = *SampleData\l : MinR = *SampleData\r : MaxL = MinL : MaxR = MinR
X + 1 : Sample = 0
EndIf
*SampleData + 4
Wend
EndIf
StopDrawing()
EndIf
EndProcedure
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)