Page 1 of 1

[Implemented] new sound functions

Posted: Tue Aug 22, 2006 4:28 pm
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

Posted: Tue Oct 10, 2006 9:13 am
by Hurga
i can only say: me too

Posted: Wed Oct 11, 2006 7:29 am
by Chrono Syndrome
Me too :)

Posted: Wed Oct 11, 2006 12:07 pm
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.

Posted: Thu Aug 28, 2008 6:29 am
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!

Posted: Thu Aug 28, 2008 10:20 am
by blueznl
+1

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

You could work around them by using your own timers, but this would make life easier :-)

Posted: Fri Aug 29, 2008 5:10 am
by jeslar360
YAY!!! Exactly what I was talking about :D

Posted: Sat Aug 30, 2008 5:41 pm
by naw
...and the ability to set the sound device to use so multiple sound cards can be supported.

Posted: Sat Aug 30, 2008 9:29 pm
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 ;-)

Posted: Tue Sep 02, 2008 12:17 am
by naw
...and while we're on the subject, the ability to change the tempo and pitch of a soundfile would be very useful...

Posted: Thu Sep 04, 2008 2:03 am
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! ;)

Posted: Thu Sep 04, 2008 5:35 pm
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...

Re: new sound functions

Posted: Sat Mar 19, 2011 12:53 pm
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