SoundPlay Questions

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

SoundPlay Questions

15 Oct 2013, 00:35

With flash it is possible to have more than one sound playing at once. SoundPlay doesn't appear to support this. Is there an alternative to using SoundPlay? We have a Windows 8 PC and bluetooth speakers. When using Soundplay short mp3 and wav files (less than a second) are being truncated. Is there any solution to buffer the whole sound before it is played? Thanks.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: SoundPlay Questions

15 Oct 2013, 07:26

Example 1 - winmm.dll:

Code: Select all

MusicFile := "F:\Music\test.mp3"
mciSendString("open " """" MusicFile """" " type mpegvideo Alias MyMusic")
mciSendString("play MyMusic")
MsgBox, Playing...

ResRead( WAV01, "test.wav" )
PlaySoundAsync( WAV01 )
MsgBox, pause

; ====================================================================
mciSendString(Command) {
   Return, DllCall("winmm.dll\mciSendString", Str,Command, Str,"", Int,0, Int,0)
}

PlaySoundAsync( ByRef Sound ) { ; http://www.autohotkey.com/board/topic/96484-read-wave-resource-from-exe-using-skans-dllread-possible/?p=609800
   Return DllCall( "winmm.dll\PlaySound" ( A_IsUnicode ? "W" : "A" ), UInt,&Sound, UInt,0, UInt, 0x7 )
}

; ResRead() By SKAN, from http://www.autohotkey.com/board/topic/57631-crazy-scripting-resource-only-dll-for-dummies-36l-v07/?p=609282
ResRead( ByRef Var, Key ) { 
  VarSetCapacity( Var, 128 ), VarSetCapacity( Var, 0 )
  If ! ( A_IsCompiled ) {
    FileGetSize, nSize, %Key%
    FileRead, Var, *c %Key%
    Return nSize
  }
 
  If hMod := DllCall( "GetModuleHandle", UInt,0 )
    If hRes := DllCall( "FindResource", UInt,hMod, Str,Key, UInt,10 )
      If hData := DllCall( "LoadResource", UInt,hMod, UInt,hRes )
        If pData := DllCall( "LockResource", UInt,hData )
  Return VarSetCapacity( Var, nSize := DllCall( "SizeofResource", UInt,hMod, UInt,hRes ) )
      ,  DllCall( "RtlMoveMemory", Str,Var, UInt,pData, UInt,nSize )
Return 0    
}

; PlaySoundAsync_File( SoundFile ) {
;    Return DllCall("winmm.dll\PlaySound", "str",SoundFile, UInt,0, UInt, 0x00020000 | 0x0001 )
; }
Example 2 - bass.dll:

Code: Select all

BASS_DLLCALL	   := DllCall("LoadLibrary", "str", A_ScriptDir "\bass.dll") ; load Bass.dll
BASS_Init		   := DllCall("bass\BASS_Init", Int,-1, UInt,44100, Int,0, UInt,0, UInt,0) ;initialise Bass
BASS_start	       := DllCall("bass\BASS_Start", int) ;Start Bass

hMedia             := DllCall("bass\BASS_StreamCreateFile", Int, 0, Astr, "F:\Music\test1.mp3", Uint, 0, Uint, 0, Uint, 0, Uint, 44100)
BASS_ChannelPlay   := DllCall("bass\BASS_ChannelPlay", UInt,hMedia, Int,1) ;Starts playback

hMedia2            := DllCall("bass\BASS_StreamCreateFile", Int, 0, Astr, "F:\Music\test2.mp3", Uint, 0, Uint, 0, Uint, 0, Uint, 44100) 
BASS_ChannelPlay2  := DllCall("bass\BASS_ChannelPlay", UInt,hMedia2, Int,1) ;Starts playback

MsgBox, pause
DllCall("bass\BASS_Free") ; Free Bass Contents
DllCall("FreeLibrary", UInt, BASS_DLLCALL)
ExitApp
bass.dll can be downloaded from http://www.un4seen.com/
Zelio
Posts: 278
Joined: 30 Sep 2013, 00:45
Location: France

Re: SoundPlay Questions

15 Oct 2013, 11:26

Else, this 2 methods will work only for .wav file, check url for more flag option (async, loop, ...)

Code: Select all

FileRead, Sound1, *c %SystemRoot%\Media\tada.wav 
FileRead, Sound2, *c %SystemRoot%\Media\chimes.wav 

msgbox READY!

sndPlaySound(Sound1)
PlaySound(Sound2)

Return

;http://msdn.microsoft.com/en-us/library/windows/desktop/dd743680.aspx

sndPlaySound(ByRef Sound ) {
Return DllCall("winmm.dll\sndPlaySound", UInt, &Sound, UInt, 0x6 ) ;SND_MEMORY|SND_NODEFAULT
}

;http://msdn.microsoft.com/en-us/library/windows/desktop/dd743680.aspx

PlaySound(ByRef Sound ) {
Return DllCall("winmm.dll\PlaySound", UInt, &Sound, UInt, 0, UInt, 0x6 ) ;SND_MEMORY|SND_NODEFAULT
}
I don't found my old script but a way to play mp3 is to open the file with mcisendstring and play it at 00s when you need it. I did a game and for play sound I needed a seperated thread to have a realtime and uncut sound, also most part of lag is cause by your computer because that will use LAV or FF or other codec filter (maybe you can see extra icon when you play a mp3). There is the SOX solution too as a player.

Else for multiple SoundPlay, http://www.autohotkey.com/board/topic/5 ... d-wrapper/

Code: Select all

#Persistent

loop 10
{
SoundPlay( SystemRoot "\Media\tada.wav " , "Multi" )
sleep 50
}

SoundPlay(Filename, wait="") {
static pSoundPlay=0, File=0
  if !(pSoundPlay)
    pSoundPlay := RegisterCallback( "SoundPlay" )
  if !(Filename=0xFFFF)
    File := Filename
  if (wait="Multi") or (wait>=2)
    DllCall( "CreateThread", UInt,0, UInt,0, UInt,pSoundPlay, UInt,0xFFFF, UInt,0, UInt,0 )
  else
    SoundPlay, %File%, %wait%
return
}
However I suggest than you use first solution of tmplinshi
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: SoundPlay Questions

15 Oct 2013, 20:11

Thanks for the replies. Very interesting, though I don't fully understand them. I discovered that the Bluetooth problem is called by a A2DP delay. It's possible to work around this by having an empty sound file looping in the background so that the gate between the PC and the speakers is never closed. Is it possible to set up an endless loop? Experimenting, I tried the code below expecting to get overlapping sounds but didn't. WAV01 was replaced by WAV02:

Code: Select all

ResRead( WAV01, "L:\Chants\We all scream for ice cream.wav" )
ResRead( WAV02, "L:\Chants\Yes I do answers.wav" )

PlaySoundAsync( WAV01 )
sleep 500
PlaySoundAsync( WAV02 )

MsgBox, pause

; ====================================================================
mciSendString(Command) {
   Return, DllCall("winmm.dll\mciSendString", Str,Command, Str,"", Int,0, Int,0)
}

PlaySoundAsync( ByRef Sound ) { ; http://www.autohotkey.com/board/topic/96484-read-wave-resource-from-exe-using-skans-dllread-possible/?p=609800
   Return DllCall( "winmm.dll\PlaySound" ( A_IsUnicode ? "W" : "A" ), UInt,&Sound, UInt,0, UInt, 0x7 )
}

; ResRead() By SKAN, from http://www.autohotkey.com/board/topic/57631-crazy-scripting-resource-only-dll-for-dummies-36l-v07/?p=609282
ResRead( ByRef Var, Key ) {
  VarSetCapacity( Var, 128 ), VarSetCapacity( Var, 0 )
  If ! ( A_IsCompiled ) {
    FileGetSize, nSize, %Key%
    FileRead, Var, *c %Key%
    Return nSize
  }
 
  If hMod := DllCall( "GetModuleHandle", UInt,0 )
    If hRes := DllCall( "FindResource", UInt,hMod, Str,Key, UInt,10 )
      If hData := DllCall( "LoadResource", UInt,hMod, UInt,hRes )
        If pData := DllCall( "LockResource", UInt,hData )
  Return VarSetCapacity( Var, nSize := DllCall( "SizeofResource", UInt,hMod, UInt,hRes ) )
      ,  DllCall( "RtlMoveMemory", Str,Var, UInt,pData, UInt,nSize )
Return 0    
}
I don't get why the Msgbox completely stops the sound (or why it should pause the sound). Does it make a difference that I am using a 64 bit system? Thanks again for the replies.
Last edited by PuzzledGreatly on 17 Nov 2013, 00:18, edited 2 times in total.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: SoundPlay Questions

15 Oct 2013, 21:38

PuzzledGreatly
Sorry, I should wrote:

Code: Select all

MsgBox, Playing... (Close this MsgBox to exit.)
Try this example:

Code: Select all

MusicFile := "L:\Chants\We all scream for ice cream.wav"
mciSendString("open " """" MusicFile """" " type mpegvideo Alias WAV01")

ResRead( WAV02, "L:\Chants\Yes I do answers.wav" )

Gui, Add, Button, vbtn_play gbtn_play, Play Sound1 (Loop)
Gui, Add, Button, gbtn_play2, Play Sound2
Gui, Add, Button, vbtn_stop gbtn_stop Disabled, Stop Sound1
Gui, Show, w300 h300
Return

btn_play:
	mciSendString("play WAV01 repeat")
	GuiControl, Disable, btn_play
	GuiControl, Enable, btn_stop
Return

btn_play2:
	sndPlaySound( WAV02 )
Return

btn_stop:
	mciSendString("stop WAV01")
	; mciSendString("close WAV01")
	GuiControl, Disable, btn_stop
	GuiControl, Enable, btn_play
Return

GuiClose:
ExitApp

; ====================================================================
sndPlaySound(ByRef Sound ) {
	Return DllCall("winmm.dll\sndPlaySound", UInt, &Sound, UInt, 0x7 ) ;SND_MEMORY|SND_NODEFAULT|SND_ASYNC
}

mciSendString(Command) {
   Return, DllCall("winmm.dll\mciSendString", Str,Command, Str,"", Int,0, Int,0)
}

; ResRead() By SKAN, from http://www.autohotkey.com/board/topic/57631-crazy-scripting-resource-only-dll-for-dummies-36l-v07/?p=609282
ResRead( ByRef Var, Key ) {
  VarSetCapacity( Var, 128 ), VarSetCapacity( Var, 0 )
  If ! ( A_IsCompiled ) {
    FileGetSize, nSize, %Key%
    FileRead, Var, *c %Key%
    Return nSize
  }
 
  If hMod := DllCall( "GetModuleHandle", UInt,0 )
    If hRes := DllCall( "FindResource", UInt,hMod, Str,Key, UInt,10 )
      If hData := DllCall( "LoadResource", UInt,hMod, UInt,hRes )
        If pData := DllCall( "LockResource", UInt,hData )
  Return VarSetCapacity( Var, nSize := DllCall( "SizeofResource", UInt,hMod, UInt,hRes ) )
      ,  DllCall( "RtlMoveMemory", Str,Var, UInt,pData, UInt,nSize )
Return 0    
}

PlaySoundLoop( ByRef Sound ) {
   Return DllCall( "winmm.dll\PlaySound", UInt,&Sound, UInt,0, UInt, 0x0004|0x0001|0x0002|0x0008 ) ; SND_MEMORY|SND_ASYNC|SND_NODEFAULT|SND_LOOP
}
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: SoundPlay Questions

16 Oct 2013, 00:19

Thanks, the looping works. I'm still trying to understand the model. What would I do if I wanted a third sound or to loop two sounds?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: SoundPlay Questions

16 Oct 2013, 07:03

Code: Select all

File_WAV01 := "e:\1.wav"
File_WAV02 := "e:\2.wav"
File_WAV03 := "e:\3.wav"
File_WAV04 := "e:\4.wav"

Gui, Add, Checkbox, vEnableWAV01 gPlay1, Loop WAV01
Gui, Add, Checkbox, vEnableWAV02 gPlay2, Loop WAV02
Gui, Add, Button, gPlay3, Play WAV03
Gui, Add, Button, gPlay4, Play WAV04
Gui, Show, w300 h300
Return

Play1:
  GuiControlGet, EnableWAV01
  if EnableWAV01
    PlayMusic(File_WAV01, "Song1", "repeat")
  else
    StopMusic("Song1")
Return

Play2:
  GuiControlGet, EnableWAV02
  if EnableWAV02
    PlayMusic(File_WAV02, "Song2", "repeat")
  else
    StopMusic("Song2")
Return

Play3:
  CloseMusic("Song3")
  PlayMusic(File_WAV03, "Song3")
Return

Play4:
  CloseMusic("Song4")
  PlayMusic(File_WAV04, "Song4")
Return

GuiClose:
ExitApp

; ====================================================================
PlayMusic(MusicFile, MusicAlias, Flags="") { ; Flags: repeat, etc...
  mciSendString("open " """" MusicFile """" " type mpegvideo Alias " MusicAlias)
  mciSendString("play " MusicAlias " " Flags)
}

StopMusic(MusicAlias) {
  mciSendString("stop " MusicAlias)
}

CloseMusic(MusicAlias) {
  mciSendString("close " MusicAlias)
}

mciSendString(Command) {
  Return, DllCall("winmm.dll\mciSendString", Str,Command, Str,"", Int,0, Int,0)
}
It seems if a song didn't play with "repeat" flag, next time you need to close that MusicAlias, and reopen it to play.
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: SoundPlay Questions

16 Oct 2013, 20:44

Thanks, the example is great. I really appreciate the time you've taken to put these all these examples together. Is there a full list of flags, anywhere?. On the [link=http://msdn.microsoft.com/en-us/library ... }Microsoft Page[/link] repeat is listed as SND_LOOP.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: SoundPlay Questions

17 Oct 2013, 06:23

The flags of play command can be found on this page:
http://msdn.microsoft.com/en-us/library ... s.85).aspx

The mciSendString commands list:
http://msdn.microsoft.com/en-us/library ... s.85).aspx

hmm... I should provide links like Zelio did :P. Sorry PuzzledGreatly waste your time to ask for the link.
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: SoundPlay Questions

17 Oct 2013, 07:37

No problem, Thank s for the links. Looks like some very interesting stuff to experiment with.
stealzy
Posts: 91
Joined: 01 Nov 2015, 13:43

Re: SoundPlay Questions

06 Nov 2017, 07:41

I'm trying to use multi-thread method, seems it stop work after 9 thread:

Code: Select all

filePath = D:\YourFile.wav

i:=0
Loop 12 {
	ToolTip % ++i
	SoundPlay(filePath, true)
	Sleep 1000
}

F1::SoundPlay(filePath, true)  ; a
Esc::ExitApp

SoundPlay(file, newThread:=false) {
	static pSoundPlay, filePath
	if !pSoundPlay
		pSoundPlay := RegisterCallback("SoundPlay")

	if newThread {
		filePath := file
		Handle := DllCall("CreateThread", Ptr, 0, Ptr, 0, Ptr, pSoundPlay, Ptr, 0, UInt, 0, Ptr, 0)
		DllCall("CloseHandle", UInt, Handle)
	} else {
		SoundPlay % filePath, % wait
		DllCall("ExitThread")
	}
}
If comment DllCall("ExitThread") line, it increase to about 30 thread:

Code: Select all

filePath = D:\YourFile.wav

i:=0
Loop 50 {
	ToolTip % ++i
	SoundPlay(filePath, true)
	Sleep 200
}

F1::SoundPlay(filePath, true)  ; a
Esc::ExitApp

SoundPlay(file, newThread:=false) {
	static pSoundPlay, filePath
	if !pSoundPlay
		pSoundPlay := RegisterCallback("SoundPlay")

	if newThread {
		filePath := file
		Handle := DllCall("CreateThread", Ptr, 0, Ptr, 0, Ptr, pSoundPlay, Ptr, 0, UInt, 0, Ptr, 0)
		DllCall("CloseHandle", UInt, Handle)
	} else {
		SoundPlay % filePath, % wait
		; DllCall("ExitThread")
	}
}
Does anyone know the right way to call new threads?
stealzy
Posts: 91
Joined: 01 Nov 2015, 13:43

Re: SoundPlay Questions

06 Nov 2017, 16:59

Also new thread does not help in case of use DllCall winmm.dll\PlaySound.
А new sound completes the current playing sound, like calling several SoundPlay, file.wav command from one thread:

Code: Select all

FileRead WAV01, *c D:\dtmf.wav
FileRead WAV02, *c C:\explode.wav
FileRead WAV03, *c C:\applause.wav
FileRead WAV04, *c C:\chimes.wav
ArrWAV:={WAV01: &WAV01, WAV02: &WAV02, WAV03: &WAV03, WAV04: &WAV04}
Loop 4
	Gui Add, Button, gPlay, WAV0%A_Index%
Gui Show, w200
Return

Play:
	SoundPlay(ArrWAV[A_GuiControl], false)
	Return

SoundPlay(Bin, Callback:=true) {
	static pSoundPlay:=0
	if !pSoundPlay
		pSoundPlay := RegisterCallback("SoundPlay")
	if Callback
		PlaySound(Bin)
	else
		DllCall("CreateThread", UInt,0, UInt,0, UInt,pSoundPlay, Ptr,Bin, UInt,0, UInt,0)
	Return
}
PlaySound(ByRef hSound) {
	Return DllCall("winmm.dll\PlaySound" (A_IsUnicode ? "W" : "A"), UInt, hSound, UInt, 0, UInt, 0x7)
}

Esc::
GuiClose:
	ExitApp
newBie1234
Posts: 1
Joined: 31 Jul 2020, 00:12

Re: SoundPlay Questions

31 Jul 2020, 00:20

tmplinshi wrote:
15 Oct 2013, 21:38
PuzzledGreatly
Sorry, I should wrote:

Code: Select all

MsgBox, Playing... (Close this MsgBox to exit.)
Try this example:

Code: Select all

MusicFile := "L:\Chants\We all scream for ice cream.wav"
mciSendString("open " """" MusicFile """" " type mpegvideo Alias WAV01")

ResRead( WAV02, "L:\Chants\Yes I do answers.wav" )

Gui, Add, Button, vbtn_play gbtn_play, Play Sound1 (Loop)
Gui, Add, Button, gbtn_play2, Play Sound2
Gui, Add, Button, vbtn_stop gbtn_stop Disabled, Stop Sound1
Gui, Show, w300 h300
Return

btn_play:
	mciSendString("play WAV01 repeat")
	GuiControl, Disable, btn_play
	GuiControl, Enable, btn_stop
Return

btn_play2:
	sndPlaySound( WAV02 )
Return

btn_stop:
	mciSendString("stop WAV01")
	; mciSendString("close WAV01")
	GuiControl, Disable, btn_stop
	GuiControl, Enable, btn_play
Return

GuiClose:
ExitApp

; ====================================================================
sndPlaySound(ByRef Sound ) {
	Return DllCall("winmm.dll\sndPlaySound", UInt, &Sound, UInt, 0x7 ) ;SND_MEMORY|SND_NODEFAULT|SND_ASYNC
}

mciSendString(Command) {
   Return, DllCall("winmm.dll\mciSendString", Str,Command, Str,"", Int,0, Int,0)
}

; ResRead() By SKAN, from http://www.autohotkey.com/board/topic/57631-crazy-scripting-resource-only-dll-for-dummies-36l-v07/?p=609282
ResRead( ByRef Var, Key ) {
  VarSetCapacity( Var, 128 ), VarSetCapacity( Var, 0 )
  If ! ( A_IsCompiled ) {
    FileGetSize, nSize, %Key%
    FileRead, Var, *c %Key%
    Return nSize
  }
 
  If hMod := DllCall( "GetModuleHandle", UInt,0 )
    If hRes := DllCall( "FindResource", UInt,hMod, Str,Key, UInt,10 )
      If hData := DllCall( "LoadResource", UInt,hMod, UInt,hRes )
        If pData := DllCall( "LockResource", UInt,hData )
  Return VarSetCapacity( Var, nSize := DllCall( "SizeofResource", UInt,hMod, UInt,hRes ) )
      ,  DllCall( "RtlMoveMemory", Str,Var, UInt,pData, UInt,nSize )
Return 0    
}

PlaySoundLoop( ByRef Sound ) {
   Return DllCall( "winmm.dll\PlaySound", UInt,&Sound, UInt,0, UInt, 0x0004|0x0001|0x0002|0x0008 ) ; SND_MEMORY|SND_ASYNC|SND_NODEFAULT|SND_LOOP
}
Hello tmplinshi and PuzzledGreatly.
Thanks for this nice script.
If I want to speed up/down the sound, what should i have to do? I try mciSendTring("play MyMusic fast/slow/speed") but it seems not to work.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 339 guests