Jump to content
Sign in to follow this  
XKahn

The Best Way to Play Sounds?

Recommended Posts

XKahn

Hello All,

I am farting around using SoundPlay and variations. I came across a script that loads the media player as an object and was just wondering how to loop the sound or make a routine where once the sound file is done to play another.

Here are some functions I created while doing this:

Global $oPlayer1 = ObjCreate("Wmplayer.OCX")
Global $oPlayer2 = ObjCreate("Wmplayer.OCX")
Global $oPlayer3 = ObjCreate("Wmplayer.OCX")
Global $oPlayer4 = ObjCreate("Wmplayer.OCX")


Func Get_Music ()
        $song = Search_Files("music","*.mp3")
        $oPlayer1.url = "music\" & $song
        if WMGetState($oPlayer1) <> "Playing" Then
            Sleep (500)
        EndIf
;This also works but has no multi-track ability. 
        ;SoundPlay ("music\" & $song) 
EndFunc

Func Search_Files($folder,$crit)
    $default = @WorkingDir
    FileChangeDir($folder)
    $i = 0
    $search = FileFindFirstFile($crit)  
    
    If $search = -1 Then
        $i = 0
    Else
        $file = FileFindNextFile($search)
        While not @error
            $i += 1
            $file = FileFindNextFile($search)
        WEnd

        FileClose($search)
        $j = Random (1,$i,1)
        $search = FileFindFirstFile($crit) 
        While $j > 0
            $file = FileFindNextFile($search)           
            $j -= 1
        WEnd
        FileClose($search)
    EndIf
    FileChangeDir($default)
    Return $file
EndFunc
;This function is not my work but found on this forum. 
Func WMGetState($wm_obj)
local $sStates = "Undefined,Stopped,Paused,Playing,ScanForward,ScanReverse,Buffering,"
$sStates &= "Waiting,MediaEnded,Transitioning,Ready,Reconnecting"
local $aStates = StringSplit($sStates, ",")
$iState = $wm_obj.playState ()
Return $aStates[$iState]
EndFunc

I would like to know why sometimes the music seems to be not loading using the Get_Music() above. I am thinking it must be in my own Search_Files($folder,$crit) function. Basically it goes to the folder and loads a random tune but sometimes it plays nothing at all. I was thinking I should just use calls to the winmm.dll instead?

Opinions?

Share this post


Link to post
Share on other sites
Ascend4nt

Check out mciSendString on MSDN. It allows you to play all different types of media without requiring much interaction on your behalf - and additionally can send a 'MM_MCINOTIFY' message to a function once it is done playing.

An example I used to play a MIDI file for a max of 60 seconds:

Global $bDonePlaying=False

Func _MM_MCINOTIFY($hWnd,$Msg, $wParam, $lParam)
    ConsoleWrite("MM_MCINOTIFY command received! $hWnd="&$hWnd&", $Msg="&$Msg&", $wParam="&$wParam&", $lParam="&$lParam&@CRLF)
    $bDonePlaying=True
EndFunc


Func _MCISendCommand($sCmd,$hWnd=0)
    Local $aRet=DllCall("winmm.dll","dword","mciSendStringW","wstr",$sCmd,"wstr","","uint",65536,"handle",$hWnd)
    If @error Then Return SetError(2,@error,"")
    If $aRet[0] Then Return SetError(3,0,$aRet[0])
    Return $aRet[2]
EndFunc

$hTemp=GUICreate("")
GUIRegisterMsg(0x3B9,"_MM_MCINOTIFY")   ; MM_MCINOTIFY  0x3B9
_MCISendCommand('open "'&@ScriptDir&'\[Bundled_Files]\THE_RAIN.MID" type sequencer alias TheRain')
_MCISendCommand('play TheRain notify',$hTemp)
$iTimer=TimerInit()
$iMaxTime=6
While Not $bDonePlaying
    Sleep(10)
    If TimerDiff($iTimer)>10000 Then
        $iMaxTime-=1
        If $iMaxTime<1 Then
            ConsoleWrite("Okay, 60 seconds is enough.. stopping play"&@CRLF)
            _MCISendCommand('stop TheRain notify')
        Else
            ConsoleWrite("10 more seconds passed.."&@CRLF)
        EndIf
        $iTimer=TimerInit()
    EndIf
WEnd
_MCISendCommand('close TheRain')

*edit: forgot link

Edited by Ascend4nt

Share this post


Link to post
Share on other sites
AdmiralAlkex

As far as I know there are 2 big udf's so far. The Sound UDF included with AutoIt (look at Sound Management in helpfile) and BASS UDF (in the examples forum). Unless you need the extra formats BASS can do, I would suggest you use the former. It uses winmm.dll if that's what you like.

To make a loop, or play next file after current is ended, you need to have a loop/adlib that checks the status. Same thing whatever UDF you use.

Quick example:

#include <Sound.au3>
#Include <File.au3>

$folder = FileSelectFolder("Select folder to play mp3's from", "")

$list = _FileListToArray($folder, "*.mp3" , 1)

For $iX = 1 To $list[0]
    $song = _SoundOpen($folder & "\" & $list[$iX])
    _SoundPlay($song)
    Do
        Sleep(100)
    Until _SoundStatus($song) = "stopped"
    _SoundClose($song)
Next

Share this post


Link to post
Share on other sites
Ascend4nt

AdmiralAlkex, I hadn't even noticed the Sound UDF uses the MCI interface. How unfortunate the UDF doesn't include a callback option. It's easy to implement as evidenced in my script above.

Share this post


Link to post
Share on other sites
AdmiralAlkex

It misses a lot of stuff, like change speed and change volume. Fortunately someone else had already done them when I needed those features in EMP.

My post with some code.

Edit: Changed link

Edited by AdmiralAlkex

Share this post


Link to post
Share on other sites
XKahn

Well thanks a bunch guys for all the info. Yes, AdmiralAlkex I am very familiar with the mciSendString and was wondering if AutoIt had anything I hadn't tried out yet in the sound options. Apparently my problem was actually inside this snippet I took from this forum. Apparently the string that defines the states is offset, I had to realign it. 1 = stopped 2 = pause and so on. My loop was waiting for the media to stop and that never came so the program waited.

Func WMGetState($wm_obj)
local $sStates = "Undefined,Stopped,Paused,Playing,ScanForward,ScanReverse,Buffering,"
$sStates &= "Waiting,MediaEnded,Transitioning,Ready,Reconnecting"
local $aStates = StringSplit($sStates, ",")
$iState = $wm_obj.playState ()
Return $aStates[$iState]
EndFunc

So I made my loop pretty simple like this instead.

$msg = GUIGetMsg()
While $msg <> $GUI_EVENT_CLOSE
    $msg = GUIGetMsg()
    If $oPlayer1.playState () = 1 Then
        Get_Music ()
    EndIf
WEnd

Now when the song stops it jumps to my Get_Music() and pulls up the next MP3 at random.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.