[Implemented] new sound functions

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

[Implemented] new sound functions

Post by Dr. Dri »

The Sound lib doesn't give any control to the user. There is no sync possible so I tried to get some more features myself and now I know what's possible for windows... Channels are not documented so i don't include them as i don't know how they do work.

Code: Select all

new names for existing functions

SetSoundFrequency(Sound, Frequency) (instead of SoundFrequency)
SetSoundPan(Sound, Pan) (instead of SoundPan)
SetSoundVolume(Sound, Volume) (instead of SoundVolume)

of course the Get recurring functions

GetSoundFrequency(Sound)
GetSoundPan(Sound)
GetSoundVolume(Sound)

time functions (in milliseconds)

SeSoundPosition(Sound, Position)
GetSoundPosition(Sound)
SoundLength(Sound) ;depends on frequency
SoundRealLength(Sound)

playing functions

PauseSound(Sound)
ResumeSound(Sound) ;do not play if stopped ?
SoundStatus(Sound)

and status constants

#PB_Sound_Stopped
#PB_Sound_Playing
#PB_Sound_Paused

maybe a flag for LoadSound ?
Something like #PB_Sound_Music for streaming
i wish i could do this kind of program with native functions ^^

Code: Select all

Structure WAVEFORMATEX Extends WAVEFORMAT
  nBitsPerSample.l
EndStructure

Structure DSBCAPS
  dwSize.l
  dwFlags.l
  dwBufferBytes.l
  dwUnlockTransferRate.l
  dwPlayCpuOverhead.l
EndStructure

Procedure.l SoundID(Sound.l)
  Protected *SoundID.Long
  
  *SoundID = IsSound(Sound)
  
  If *SoundID
    *SoundID = *SoundID\l
  EndIf
  
  ProcedureReturn *SoundID
EndProcedure

Procedure.l GetSoundFrequency(Sound.l)
  Protected Frequency.l
  Protected *SoundID.Long
  Protected Buffer.IDirectSoundBuffer
  
  *SoundID = IsSound(Sound)
  
  If *SoundID
    Buffer = *SoundID\l
  EndIf
  
  If Buffer
    Buffer\GetFrequency(@Frequency)
  EndIf
  
  ProcedureReturn Frequency
EndProcedure

Procedure.l GetSoundPosition(Sound.l)
  Protected Position.q
  Protected Frequency.l
  Protected *SoundID.Long
  Protected Format.WAVEFORMATEX
  Protected Buffer.IDirectSoundBuffer
  
  *SoundID = IsSound(Sound)
  
  If *SoundID
    Buffer = *SoundID\l
  EndIf
  
  If Buffer
    Buffer\GetCurrentPosition(@Position, #Null)
    Buffer\GetFrequency(@Frequency)
    Buffer\GetFormat(Format, SizeOf(WAVEFORMATEX), #Null)
    Format\nBitsPerSample / 8
  EndIf
  
  If Frequency And Format\nChannels And Format\nBitsPerSample
    Position * 1000 ;milliseconds
    Position / Format\nChannels
    Position / Format\nBitsPerSample
    Position / Frequency
  Else
    Position = -1
  EndIf
  
  ProcedureReturn Position
EndProcedure

Procedure.l SoundLength(Sound.l)
  Protected Length.q
  Protected Frequency.l
  Protected *SoundID.Long
  Protected Caps.DSBCAPS
  Protected Format.WAVEFORMATEX
  Protected Buffer.IDirectSoundBuffer
  
  *SoundID = IsSound(Sound)
  
  If *SoundID
    Buffer = *SoundID\l
  EndIf
  
  If Buffer
    Caps\dwSize = SizeOf(DSBCAPS)
    
    Buffer\GetCaps(Caps)
    Buffer\GetFrequency(@Frequency)
    Buffer\GetFormat(Format, SizeOf(WAVEFORMATEX), #Null)
    
    Length = Caps\dwBufferBytes
    Format\nBitsPerSample / 8
  EndIf
  
  If Length And Frequency And Format\nChannels And Format\nBitsPerSample
    Length * 1000 ;milliseconds
    Length / Format\nChannels
    Length / Format\nBitsPerSample
    Length / Frequency
  Else
    Length = -1
  EndIf
  
  ProcedureReturn Length
EndProcedure

Procedure.l SoundRealLength(Sound.l)
  Protected Length.q
  Protected *SoundID.Long
  Protected Caps.DSBCAPS
  Protected Format.WAVEFORMATEX
  Protected Buffer.IDirectSoundBuffer
  
  *SoundID = IsSound(Sound)
  
  If *SoundID
    Buffer = *SoundID\l
  EndIf
  
  If Buffer
    Caps\dwSize = SizeOf(DSBCAPS)
    
    Buffer\GetCaps(Caps)
    Buffer\GetFormat(Format, SizeOf(WAVEFORMATEX), #Null)
    
    Length = Caps\dwBufferBytes
    Format\nBitsPerSample / 8
  EndIf
  
  If Length And Format\nSamplesPerSec And Format\nChannels And Format\nBitsPerSample
    Length * 1000 ;milliseconds
    Length / Format\nChannels
    Length / Format\nBitsPerSample
    Length / Format\nSamplesPerSec
  Else
    Length = -1
  EndIf
  
  ProcedureReturn Length
EndProcedure

InitSound()
UseOGGSoundDecoder()

If OpenWindow(0, 0, 0, 270, 160, "Sound Enhancement", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CreateGadgetList(WindowID(0))
  
  ;fixed font gadgets
  TextGadget(0, 10,  10, 250, 20, "", #PB_Text_Right)
  TextGadget(1, 10,  40, 250, 20, "", #PB_Text_Right)
  TextGadget(2, 10,  70, 250, 20, "", #PB_Text_Right)
  TextGadget(3, 10, 100, 250, 20, "", #PB_Text_Right)
  
  For i = 0 To 3
    SetGadgetFont(i, GetStockObject_(#ANSI_FIXED_FONT))
  Next i
  
  ;updates the gadgets
  SetTimer_(WindowID(0), 1, 50, 0)
  
  ;loads a sound ^_^
  Repeat
    file$ = OpenFileRequester("Open a music file", "", "Music file | *.wav;*.ogg", 0)
    LoadSound(0, file$)
  Until IsSound(0)
  
  ;length a position depend on Frequency
  ;you can try it a bit faster ;)
  SoundFrequency(0, GetSoundFrequency(0) * 1.5)
  
  ;length is unsigned long so a quad is more simple
  ;than using the "length & $FFFFFFFF" trick
  length.q = SoundRealLength(Sound.l)
  mil = length % 1000
  
  length / 1000
  sec = length % 60
  
  min = length / 60
  
  ;display the real length
  Text$ = Str(min) + ":" + RSet(Str(sec), 2, "0") + ":"  + RSet(Str(mil/10), 2, "0")
  SetGadgetText(3, "Real length -> " + Text$)
  
  length.q = SoundLength(Sound.l)
  mil = length % 1000
  
  length / 1000
  sec = length % 60
  
  min = length / 60
  
  ;display the length
  Text$ = Str(min) + ":" + RSet(Str(sec), 2, "0") + ":"  + RSet(Str(mil/10), 2, "0")
  SetGadgetText(2, "Length -> " + Text$)
  
  ;progressbar from pos 0 to length/1000
  ProgressBarGadget(4, 10, 130, 250, 20, 0, length, #PB_ProgressBar_Smooth)
  
  ;here we go
  PlaySound(0)
  start = ElapsedMilliseconds()
  
  Repeat
    Event = WaitWindowEvent()
    
    If Event = #WM_TIMER
      ;display the software position
      pos.q = ElapsedMilliseconds() - start
      SetGadgetText(0, Hex(pos))
      mil = pos % 1000
      
      pos / 1000
      sec = pos % 60
      
      min = pos / 60
      
      Text$ = Str(min) + ":" + RSet(Str(sec), 2, "0") + ":"  + RSet(Str(mil/10), 2, "0")
      SetGadgetText(1, "Software position -> " + Text$)
      
      ;display the hardware position
      pos.q = GetSoundPosition(0)
      SetGadgetText(0, Hex(pos))
      mil = pos % 1000
      
      pos / 1000
      sec = pos % 60
      
      min = pos / 60
      
      Text$ = Str(min) + ":" + RSet(Str(sec), 2, "0") + ":"  + RSet(Str(mil/10), 2, "0")
      SetGadgetText(0, "Hardware position -> " + Text$)
      
      ;update progressbar from hardware pos/1000
      SetGadgetState(4, pos)
    EndIf
    
  Until Event = #PB_Event_CloseWindow
EndIf
Dri
Hurga
Enthusiast
Enthusiast
Posts: 148
Joined: Thu Jul 17, 2003 2:53 pm
Contact:

Post by Hurga »

i can only say: me too
Chrono Syndrome
Enthusiast
Enthusiast
Posts: 169
Joined: Thu Oct 05, 2006 6:44 am
Contact:

Post by Chrono Syndrome »

Me too :)
Don't try to catch ze Night !
Remember: 'z' is better zen 'th' =) !
Sorry for bad english.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Not the first time this has been requested, but it's so important I gotta bump this thread as well!

With sync features it would be possible for us to make our own streaming playback very easily.
jeslar360
User
User
Posts: 20
Joined: Thu Aug 28, 2008 6:24 am

Post by jeslar360 »

I want to see more sound controls as well.

I want to be able to get the current playback position...as well as set the position, in a way that is platform independent.

Would also like to see built in functions for the microphone...and maybe an encoder (like there are for images). So...

BUMP!
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

+1

GetSoundPosition()
SetSoundPostion()
IsSoundPlaying()
SoundLength()
FadeSound()

You could work around them by using your own timers, but this would make life easier :-)
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
jeslar360
User
User
Posts: 20
Joined: Thu Aug 28, 2008 6:24 am

Post by jeslar360 »

YAY!!! Exactly what I was talking about :D
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

...and the ability to set the sound device to use so multiple sound cards can be supported.
Last edited by naw on Sat Aug 30, 2008 5:43 pm, edited 1 time in total.
Ta - N
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

naw wrote:...and the ability to set the sound device to use so multiple sound cards can be supported.
Now we're talking! Imagine the first game in PureBasic supporting multiple sound cards simultaneously ;-)
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

...and while we're on the subject, the ability to change the tempo and pitch of a soundfile would be very useful...
Ta - N
jeslar360
User
User
Posts: 20
Joined: Thu Aug 28, 2008 6:24 am

Post by jeslar360 »

naw wrote:...and while we're on the subject, the ability to change the tempo and pitch of a soundfile would be very useful...
Don't forget about changing frequency! And why only to a file? Why not to sounds in memory? THINK BOLD! ;)
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

jeslar360 wrote: Don't forget about changing frequency! And why only to a file? Why not to sounds in memory? THINK BOLD! ;)
Well, yes - thats what I meant really.
ie: load an MP3 / WAV etc, and play it with an altered Tempo / Pitch.
IMO Pitch=Frequency though my terminology may be wrong...
Ta - N
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: new sound functions

Post by c4s »

Sorry, I know the PB team doesn't like bumps but here it's just too important: PureBasic really needs more sound functions!

Everyone who does something with sounds, will soon get the urgend need for basic functions like:
  • GetSoundPosition(), SetSoundPostion()
  • SoundLength()
  • PauseSound(), ResumeSound()
  • SoundStatus() = #PB_Sound_Stopped, #PB_Sound_Playing, #PB_Sound_Paused
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Post Reply