Page 1 of 1

PlaySound() in end of Thread

Posted: Sun Jul 18, 2010 4:33 pm
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.

Re: PlaySound() in end of Thread

Posted: Sun Jul 18, 2010 10:13 pm
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"

Re: PlaySound() in end of Thread

Posted: Sun Jul 18, 2010 10:19 pm
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

Re: PlaySound() in end of Thread

Posted: Mon Jul 19, 2010 8:34 am
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)


Re: PlaySound() in end of Thread

Posted: Mon Jul 19, 2010 8:53 pm
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

Re: PlaySound() in end of Thread

Posted: Tue Jul 20, 2010 3:48 am
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.

Re: PlaySound() in end of Thread

Posted: Tue Jul 20, 2010 3:53 am
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