PlaySound() in end of Thread

Just starting out? Need help? Post your questions and find answers here.
Phantomas
User
User
Posts: 96
Joined: Wed Jul 01, 2009 12:59 pm

PlaySound() in end of Thread

Post by Phantomas »

Hello, if I use PlaySound() in End of Thread, then Sound not played (or played shortly) because thread exiting (quit). Can I fix it without API use, only with PB?

Example:

Code: Select all

InitSound() ; This can return 0 in executable file?

#sound = 0
#sound_file = "path_to_sound_file.wav"

Procedure thread(*i_dont_know_what_for_this)
  PlaySound(#sound)
  ;Delay(1000)
EndProcedure

If LoadSound(#sound, #sound_file) = 0
  End
Else
  thread = CreateThread(@thread(), 0)
  WaitThread(thread)
EndIf
I think, solution exist like that: add Delay(sound_file_length) :?.
This may fixed in newest PB versions?

Thanks & Sorry if this trouble already discussed.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: PlaySound() in end of Thread

Post by RASHAD »

You can use MP3 file and in that case you will be using the Movie Lib
You can estimate the duration time before playing the audio file

But if you insist to Use WAV file and Thread next snippet is for Windows

Code: Select all


Global SFile$
SFile$ = "g:\projects\02 Silencio.wav"

Procedure thread(*i_dont_know_what_for_this)
PlaySound_(SFile$,0,#SND_SYNC|#SND_NODEFAULT)
EndProcedure

thread = CreateThread(@thread(), 0)
;WaitThread(thread)
While IsThread(thread)
Wend
Debug "End"
Egypt my love
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: PlaySound() in end of Thread

Post by netmaestro »

Your thread must indeed wait until the sound has time to play. But how long is that? For wav files, you can use the provided proc. It can be tweaked for other formats. What I'd do is use it to find the playtime of each sound file and put a constant at the top of your code for each, something like #EXPLOSION_1_MS = 1669 and then Delay(#EXPLOSION_1_MS) at the end of your thread procedure. This way you can use IncludeBinary and CatchSound(). But if you don't mind loading the sound from HD, RASHAD's solution is fine too.

Code: Select all

Procedure GetPlaytime(FileName.s)
  ; netmaestro July 2010
  
  Protected Result.l
  Protected shortFileName.s
  Protected Buffer.s
  
  #ALIAS = "WAVFILE"
  
  shortFilename = Space(#MAX_PATH)
  shortFilename = Left(shortFileName, GetShortPathName_(FileName, @shortFileName, #MAX_PATH))
  
  Result = mciSendString_("open " + shortFileName + " type waveaudio alias " + #ALIAS + " wait", "", 0, 0)
  If Result = 0 
    Buffer = Space(128)
    Result = mciSendString_("status " + #ALIAS + " length wait", Buffer, Len(Buffer), 0)
  Else 
    ProcedureReturn 0
  EndIf
  
  mciSendString_("close " + #ALIAS, "", 0, 0)
  
 ProcedureReturn Val(Buffer)
  
EndProcedure
BERESHEIT
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: PlaySound() in end of Thread

Post by RASHAD »

Playing WAV sound after calculating duration time
NO API ,Tested but not too much

Code: Select all


Global FName$
InitSound() ; This can return 0 in executable file?

FName$ = "G:\Projects\02 Silencio.wav"

Procedure thread(*i_dont_know_what_for_this)
 ReadFile(0, FName$) 
  length = Lof(0)
  FileSeek(0,28)
  *MemoryID = AllocateMemory(4)
  If *MemoryID
    bytes = ReadData(0, *MemoryID, 4)
    DTime = length/PeekL(*MemoryID) + 1
  EndIf
 FreeMemory(*MemoryID)
CloseFile(0)
LoadSound(0,FName$)   
PlaySound(0)
Delay(DTime*1000)
EndProcedure

thread = CreateThread(@thread(), 0)
WaitThread(thread)

Egypt my love
User avatar
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: PlaySound() in end of Thread

Post by Michael Vogel »

Another possibility is to use MCI (a relict from old windows versions), which works fine with different file formats...

There are a couple of commands available, after you have loaded a song...
mciSendString_("open " + #DQUOTE$+ActSongFile+#DQUOTE$ + " type mpegvideo alias song3", 0, 0, 0)

...you can start playing...
mciSendString_("play song3", 0, 0, 0)

...get the music length...
Dummy.s=Space(#MAX_PATH)
mciSendString_("status song3 length",Dummy,#MAX_PATH,0)
ActLength=Val(Dummy)


...and check if the song has reached the end position...
Dummy.s=Space(#MAX_PATH)
mciSendString_("status song3 position",Dummy,#MAX_PATH,0)
SongPosition=Val(Dummy)
If ActLength
If SongPosition=ActLength
Finished!!!
EndIf
EndIf
clover
User
User
Posts: 14
Joined: Tue Dec 30, 2008 4:43 am

Re: PlaySound() in end of Thread

Post by clover »

It seems that PlaySound() implements asynchronously. So you can get the total duration of the sound in advance of playing, then call Sleep() and set the param to the duration you have just got. And then... all is OK!
As for the way of getting the duration of the sound, you can refer to relative documents according to the sound format.
clover
User
User
Posts: 14
Joined: Tue Dec 30, 2008 4:43 am

Re: PlaySound() in end of Thread

Post by clover »

Below is a section of code for attaining the duration of FLAC audio files:

Code: Select all

Procedure.i GetFlacDuration(*pData)  ;return milliseconds
    If *pData = #Null
        ProcedureReturn 0
    EndIf
    
    If PeekS(*pData, 4, #PB_Ascii) <> "fLaC"
        ProcedureReturn 0
    EndIf
    
    mbs.METADATA_BLOCK_STREAMINFO
    CopyMemory(*pData + 4 + SizeOf(METADATA_BLOCK_HEADER), @mbs, SizeOf(METADATA_BLOCK_STREAMINFO))
    
    ;FLAC is big endian
    ;x86 CPU is little endian
    sample_rate.l = 0
    PokeA(@sample_rate + 2, mbs\sample_feature[0])
    PokeA(@sample_rate + 1, mbs\sample_feature[1])
    PokeA(@sample_rate + 0, mbs\sample_feature[2])
    sample_rate >> 4
    
    total_samples.q = 0
    PokeA(@total_samples + 4, mbs\sample_feature[3])
    PokeA(@total_samples + 3, mbs\sample_feature[4])
    PokeA(@total_samples + 2, mbs\sample_feature[5])
    PokeA(@total_samples + 1, mbs\sample_feature[6])
    PokeA(@total_samples + 0, mbs\sample_feature[7])
    total_samples & (%1111 << 32 | $ffffffff)
    
    ProcedureReturn Round(total_samples / sample_rate * 1000, #PB_Round_Up)
EndProcedure
Post Reply