Jump to content

Sound UDF


RazerM
 Share

Recommended Posts

Thanks, that should have been there from the start :P

My Programs:AInstall - Create a standalone installer for your programUnit Converter - Converts Length, Area, Volume, Weight, Temperature and Pressure to different unitsBinary Clock - Hours, minutes and seconds have 10 columns each to display timeAutoIt Editor - Code Editor with Syntax Highlighting.Laserix Editor & Player - Create, Edit and Play Laserix LevelsLyric Syncer - Create and use Synchronised Lyrics.Connect 4 - 2 Player Connect 4 Game (Local or Online!, Formatted Chat!!)MD5, SHA-1, SHA-256, Tiger and Whirlpool Hash Finder - Dictionary and Brute Force FindCool Text Client - Create Rendered ImageMy UDF's:GUI Enhance - Enhance your GUIs visually.IDEA File Encryption - Encrypt and decrypt files easily! File Rename - Rename files easilyRC4 Text Encryption - Encrypt text using the RC4 AlgorithmPrime Number - Check if a number is primeString Remove - remove lots of strings at onceProgress Bar - made easySound UDF - Play, Pause, Resume, Seek and Stop.
Link to comment
Share on other sites

  • Replies 59
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

New beta:

#include <Date.au3>
#include <File.au3>
#include <String.au3>
;===============================================================================
;
; Function Name:   _SoundOpen
; Description::    Opens a sound file for use with other _Sound functions
; Parameter(s):    $sFile - The sound file, $sAlias[optional] - a name such as sound1,
;                  if you do not specify one it is randomly generated
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): string(the sound id) - Success, 0 - Failure
;                  @extended <> 0 - open failed, @error = 2 - File doesn't exist,
;                  @error = 3 - alias contains whitespace
; Author(s):       RazerM, Melba23, some code by Simucal, PsaltyDS
;
;===============================================================================
;
Func _SoundOpen($sFile, $sAlias = "")
    ;Declare variables
    Local $aSndID[3], $sSndID, $iCurrentPos, $iRet, $asAlias, $fTryNextMethod = False
    Local $szDrive, $szDir, $szFName, $szExt, $iSndLenMs, $iSndLenMin, $iSndLenHour, $iSndLenSecs, $sSndLenFormat
    Local $sSndDirName, $sSndFileName, $sSndDirShortName, $oShell, $oShellDir, $oShellDirFile, $sRaw, $aInfo
    Local $sTrackLength, $iSoundTicks, $iActualTicks, $iVBRRatio, $aiTime
    
    ;check for file
    If Not FileExists($sFile) Then Return SetError(2, 0, 0)
    ;search for whitespace by character
    $asAlias = StringSplit($sAlias, "")
    For $iCurrentPos = 1 To $asAlias[0]
        If StringIsSpace($asAlias[$iCurrentPos]) Then Return SetError(3, 0, 0)
    Next
    ;create random alias if one is not supplied
    If $sAlias = "" Then
        $sSndID = __RandomStr(10)
    Else
        $sSndID = $sAlias
    EndIf
    
    If StringInStr($sSndID, '!') Then Return SetError(3, 0, 0) ;invalid file/alias
    
    $aSndID[0] = $sSndID
    
    _PathSplit($sFile, $szDrive, $szDir, $szFName, $szExt)

    If $szDrive = "" Then
        $sSndDirName = @WorkingDir & "\" 
    Else
        $sSndDirName = $szDrive & $szDir
    EndIf
    $sSndFileName = $szFName & $szExt

    $sSndDirShortName = FileGetShortName($sSndDirName, 1)

    ;open file
    $iRet = __mciSendString("open " & FileGetShortName($sFile) & " alias " & $aSndID[0])
    
    If $szExt = ".mp3"  Then
        $sTrackLength = __ReadXingFromMP3(FileGetShortName($sSndDirName & $sSndFileName))
        If @error Then $fTryNextMethod = True
    Else
        $fTryNextMethod = True
    EndIf
    
    If $fTryNextMethod And $szExt = ".mp3"  Then
        $sTrackLength = __ReadTLENFromMP3(FileGetShortName($sSndDirName & $sSndFileName))
        If @error Then $fTryNextMethod = True
    Else
        $fTryNextMethod = True
    EndIf

    If $fTryNextMethod Then
        $fTryNextMethod = False
        $oShell = ObjCreate("shell.application")
        If IsObj($oShell) Then
            $oShellDir = $oShell.NameSpace ($sSndDirShortName)
            If IsObj($oShellDir) Then
                $oShellDirFile = $oShellDir.Parsename ($sSndFileName)
                If IsObj($oShellDirFile) Then
                    $sRaw = $oShellDir.GetDetailsOf ($oShellDirFile, -1)
                    $aInfo = StringRegExp($sRaw, ": ([0-9]{2}:[0-9]{2}:[0-9]{2})", 3)
                    If Not IsArray($aInfo) Then
                        $fTryNextMethod = True
                    Else
                        $sTrackLength = $aInfo[0]
                    EndIf
                Else
                    $fTryNextMethod = True
                EndIf
            Else
                $fTryNextMethod = True
            EndIf
        Else
            $fTryNextMethod = True
        EndIf
    EndIf
    
    If $fTryNextMethod Then
        ;tell mci to use time in milliseconds
        __mciSendString("set " & $aSndID[0] & " time format miliseconds")
        ;receive length of sound
        $iSndLenMs = __mciSendString("status " & $aSndID[0] & " length", 255)
        
        ;assign modified data to variables
        _TicksToTime($iSndLenMs, $iSndLenHour, $iSndLenMin, $iSndLenSecs)
        
        ;assign formatted data to $sSndLenFormat
        $sTrackLength = StringFormat("%02i:%02i:%02i", $iSndLenHour, $iSndLenMin, $iSndLenSecs)
        $fTryNextMethod = False
    EndIf
    
    ; Convert Track_Length to mSec
    $aiTime = StringSplit($sTrackLength, ":")
    $iActualTicks = _TimeToTicks($aiTime[1], $aiTime[2], $aiTime[3])
    
    ;tell mci to use time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    
    ;;Get estimated length
    $iSoundTicks = __mciSendString("status " & $aSndID[0] & " length", 255)

    ;Compare to actual length
    If Abs($iSoundTicks - $iActualTicks) < 1000 Then ;Assume CBR, as our track length from shell.application is only accurate within 1000ms
        $iVBRRatio = 0
    Else ;Set correction ratio for VBR operations
        $iVBRRatio = $iSoundTicks / $iActualTicks
    EndIf
    
    $aSndID[1] = $iVBRRatio
    $aSndID[2] = 0

    Return SetError(0, $iRet, $aSndID)
EndFunc   ;==>_SoundOpen

;===============================================================================
;
; Function Name:   _SoundClose
; Description::    Closes a sound
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundClose($aSndID)
    If Not IsArray($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    If __mciSendString("close " & $aSndID[0]) = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundClose

;===============================================================================
;
; Function Name:   _SoundPlay
; Description::    Plays a sound from the current position (beginning is the default)
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
;                  $fWait - If set to 1 the script will wait for the sound to finish before continuing
;                        - If set to 0 the script will continue while the sound is playing
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 - Failure
;                  @error = 2 - $fWait is invalid, @error = 1 - play failed
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundPlay($aSndID, $fWait = 0)
    ;Declare variables
    Local $iRet, $vTemp
    ;validate $fWait
    If $fWait <> 0 And $fWait <> 1 Then Return SetError(2, 0, 0)
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;if sound has finished, seek to start
    If _SoundPos($aSndID, 2) = _SoundLength($aSndID, 2) Then __mciSendString("seek " & $aSndID[0] & " to start")
    ;If $fWait = 1 then pass wait to mci
    If $fWait = 1 Then
        $iRet = __mciSendString("play " & $aSndID[0] & " wait")
    Else
        $iRet = __mciSendString("play " & $aSndID[0])
    EndIf
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundPlay

;===============================================================================
;
; Function Name: _SoundStop
; Description::    Stops the sound
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundStop($aSndID)
    ;Declare variables
    Local $iRet, $iRet2, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;seek to start
    $iRet = __mciSendString("seek " & $aSndID[0] & " to start")
    ;stop
    $iRet2 = __mciSendString("stop " & $aSndID[0])
    ;return
    If $iRet = 0 And $iRet2 = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundStop

;===============================================================================
;
; Function Name:   _SoundPause
; Description::    Pauses the sound
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundPause($aSndID)
    ;Declare variables
    Local $iRet, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;pause sound
    $iRet = __mciSendString("pause " & $aSndID[0])
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundPause

;===============================================================================
;
; Function Name:   _SoundResume
; Description::    Resumes the sound after being paused
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundResume($aSndID)
    ;Declare variables
    Local $iRet, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;resume sound
    $iRet = __mciSendString("resume " & $aSndID[0])
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundResume

;===============================================================================
;
; Function Name:   _SoundLength
; Description::    Returns the length of the sound in the format hh:mm:ss
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file,
;                  $iMode = 1 - hh:mm:ss, $iMode = 2 - milliseconds
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): Length of the sound - Success, 0 and @error = 1 - $iMode is invalid
; Author(s):       RazerM, Melba23
; Mofified:        jpm
;
;===============================================================================
;
Func _SoundLength($aSndID, $iMode = 1)
    ;Declare variables
    Local $iSndLenMs, $iSndLenMin, $iSndLenHour, $iSndLenSecs, $sSndLenFormat, $vTemp = ""
    ;validate $iMode
    If $iMode <> 1 And $iMode <> 2 Then Return SetError(1, 0, 0)
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[3]
        $aSndID = _SoundOpen($vTemp)
    EndIf
    
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;tell mci to use time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    ;receive length of sound
    $iSndLenMs = __mciSendString("status " & $aSndID[0] & " length", 255)
    If $aSndID[1] <> 0 Then $iSndLenMs = Round($iSndLenMs / $aSndID[1])
    
    If $vTemp <> "" Then _SoundClose($aSndID) ;if user called _SoundLength with a filename
    
    ;assign modified data to variables
    _TicksToTime($iSndLenMs, $iSndLenHour, $iSndLenMin, $iSndLenSecs)
    
    ;assign formatted data to $sSndLenFormat
    $sSndLenFormat = StringFormat("%02i:%02i:%02i", $iSndLenHour, $iSndLenMin, $iSndLenSecs)
    
    ;return correct variable
    If $iMode = 1 Then Return $sSndLenFormat
    If $iMode = 2 Then Return $iSndLenMs
EndFunc   ;==>_SoundLength

;===============================================================================
;
; Function Name:   _SoundSeek
; Description::    Seeks the sound to a specified time
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen (must NOT be a file), $iHour, $iMin, $iSec
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundSeek(ByRef $aSndID, $iHour, $iMin, $iSec)
    ;Declare variables
    Local $iMs = 0, $iRet, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias
    
    ;prepare mci to receive time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    ;modify the $iHour, $iMin and $iSec parameters to be in milliseconds
    ;and add to $iMs
    $iMs += $iSec * 1000
    $iMs += $iMin * 60 * 1000
    $iMs += $iHour * 60 * 60 * 1000
    If $aSndID[1] <> 0 Then
        $aSndID[2] = Round($iMs * $aSndID[1]) - $iMs
        $iMs = Round($iMs * $aSndID[1])
    EndIf
    ; seek sound to time ($iMs)
    $iRet = __mciSendString("seek " & $aSndID[0] & " to " & $iMs)
    If _SoundPos($aSndID, 2) < 0 Then $aSndID[2] = 0
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundSeek

;===============================================================================
;
; Function Name:   _SoundStatus
; Description::    All devices can return the "not ready", "paused", "playing", and "stopped" values.
;                  Some devices can return the additional "open", "parked", "recording", and "seeking" values.(MSDN)
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): Sound Status
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundStatus($aSndID)
    Local $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;return status
    Return __mciSendString("status " & $aSndID[0] & " mode", 255)
EndFunc   ;==>_SoundStatus

;===============================================================================
;
; Function Name:   _SoundPos
; Description::    Returns the current position of the song
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file,
;                  $iMode = 1 - hh:mm:ss, $iMode = 2 - milliseconds
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): Current Position - Success, @error = 1 - $iMode is invalid
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundPos($aSndID, $iMode = 1)
    ;Declare variables
    Local $iSndPosMs, $iSndPosMin, $iSndPosHour, $iSndPosSecs, $sSndPosFormat, $vTemp
    ;validate $iMode
    If $iMode <> 1 And $iMode <> 2 Then Return SetError(1, 0, 0)
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;tell mci to use time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    ;receive position of sound
    $iSndPosMs = __mciSendString("status " & $aSndID[0] & " position", 255)
    If $aSndID[1] <> 0 Then
        $iSndPosMs -= $aSndID[2]
    EndIf
    
    ;modify data and assign to variables
    _TicksToTime($iSndPosMs, $iSndPosHour, $iSndPosMin, $iSndPosSecs)

    ;assign formatted data to $sSndPosFormat
    $sSndPosFormat = StringFormat("%02i:%02i:%02i", $iSndPosHour, $iSndPosMin, $iSndPosSecs)
    ;return correct variable
    If $iMode = 1 Then Return $sSndPosFormat
    If $iMode = 2 Then Return $iSndPosMs
EndFunc   ;==>_SoundPos

;internal functions
Func __mciSendString($string, $iLen = 0)
    Local $iRet
    $iRet = DllCall("winmm.dll", "int", "mciSendStringA", "str", $string, "str", "", "long", $iLen, "long", 0)
    If Not @error Then Return $iRet[2]
EndFunc   ;==>__mciSendString

Func __RandomStr($LEN)
    Local $string
    For $iCurrentPos = 1 To $LEN
        $string &= Chr(Random(97, 122, 1))
    Next
    Return $string
EndFunc   ;==>__RandomStr

;===============================================================================
;
; Function Name:   [private] __ReadTLENFromMP3
; Description::    Used internally within this file, not for general use
; Parameter(s):    $sFile - filename of mp3
; Requirement(s):  File must be an mp3 AFAIK
; Return Value(s): Sound length (hh:mm:ss) - Success, 0 and @error = 1 - Failure
; Author(s):       Melba23
; Modified:        RazerM
;
;===============================================================================
;
Func __ReadTLENFromMP3($sFile)
    Local $hFile, $sTag, $iLengthMs, $iLengthHour, $iLengthMin, $iLengthSecs

    ; Read tag info from file
    $hFile = FileOpen($sFile, 4)
    $sTag = FileRead($hFile, 1024)
    FileClose($hFile)

    ; Check that an ID3v2.3 tag is present
    If StringLeft($sTag, 10) <> "0x49443303"  Then Return SetError(1, 0, 0)

    $iLengthMs = Number(_HexToString(StringTrimLeft($sTag, StringInStr($sTag, "544C454E") + 21)))


    If $iLengthMs > 0 Then
        _TicksToTime($iLengthMs, $iLengthHour, $iLengthMin, $iLengthSecs)
        
        ;Convert to hh:mm:ss and return
        Return StringFormat("%02i:%02i:%02i", $iLengthHour, $iLengthMin, $iLengthSecs)
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>__ReadTLENFromMP3

;===============================================================================
;
; Function Name:   [private] __ReadXingFromMP3
; Description::    Used internally within this file, not for general use
; Parameter(s):    $sFile - filename of mp3
; Requirement(s):  File must be an mp3 AFAIK
; Return Value(s): Sound length (hh:mm:ss) - Success, 0 and @error = 1 - Failure
; Author(s):       Melba23
; Modified:        RazerM
;
;===============================================================================
;
Func __ReadXingFromMP3($sFile)
    Local $hFile, $sTag, $iXingPos, $iFlags, $iFrames, $sHeader, $iMPEGByte, $iFreqByte, $iMPEGVer, $iLayerNum, $iSamples, $iFreqNum, $iFrequency, $iLengthMs, $iLengthHours, $iLengthMins, $iLengthSecs

    ; Read tag info from file
    $hFile = FileOpen($sFile, 4)
    $sTag = FileRead($hFile, 5156)
    FileClose($hFile)
    $iXingPos = StringInStr($sTag, "58696E67")
    If $iXingPos = 0 Then Return SetError(1, 0, 0)

    ; Read fields flag
    $iFlags = Number("0x" & StringMid($sTag, $iXingPos + 14, 2))
    If BitAND($iFlags, 1) = 1 Then
        $iFrames = Number("0x" & StringMid($sTag, $iXingPos + 16, 8))
    Else
        Return SetError(1, 0, 0); No frames field
    EndIf

    ; Now to find Samples per frame & Sampling rate
    ; Go back to the frame header start
    $sHeader = StringMid($sTag, $iXingPos - 72, 8)

    ; Read the relevant bytes
    $iMPEGByte = Number("0x" & StringMid($sHeader, 4, 1))
    $iFreqByte = Number("0x" & StringMid($sHeader, 6, 1))

    ; Decode them
    ; 8 = MPEG-1, 0 = MPEG-2
    $iMPEGVer = BitAND($iMPEGByte, 8)
    
    ; 2 = Layer III, 4 = Layer II, 6 = Layer I
    $iLayerNum = BitAND($iMPEGByte, 6)

    Switch $iLayerNum
        Case 6
            $iSamples = 384
        Case 4
            $iSamples = 1152
        Case 2
            Switch $iMPEGVer
                Case 8
                    $iSamples = 1152
                Case 0
                    $iSamples = 576
                Case Else
                    $iSamples = 0
            EndSwitch
        Case Else
            $iSamples = 0
    EndSwitch

    ; If not valid return
    If $iSamples = 0 Then Return SetError(1, 0, 0)

    ; 0 = bit 00, 4 = Bit 01, 8 = Bit 10
    $iFreqNum = BitAND($iFreqByte, 12)
    Switch $iFreqNum
        Case 0
            $iFrequency = 44100
        Case 4
            $iFrequency = 48000
        Case 8
            $iFrequency = 32000
        Case Else
            $iFrequency = 0
    EndSwitch

    ; If not valid return
    If $iFrequency = 0 Then Return SetError(1, 0, 0)

    ; MPEG-2 halves the value
    If $iMPEGVer = 0 Then $iFrequency = $iFrequency / 2

    ; Duration in secs = No of frames * Samples per frame / Sampling freq
    $iLengthMs = Int(($iFrames * $iSamples / $iFrequency) * 1000)

    ; Convert to hh:mm:ss and return
    _TicksToTime($iLengthMs, $iLengthHours, $iLengthMins, $iLengthSecs)

    Return StringFormat("%02i:%02i:%02i", $iLengthHours, $iLengthMins, $iLengthSecs)
EndFunc   ;==>__ReadXingFromMP3

Changes:

  • _SoundPos() reporting incorrect value for long audio files.
  • _SoundLength() reports correct length with filenames now.
  • Added Xing and TLEN methods for mp3 files.
  • Internal functions use double underscores now.
  • Changed variable names to improve readability.
  • Now uses _TicksToTime() and _TimeToTicks().
My Programs:AInstall - Create a standalone installer for your programUnit Converter - Converts Length, Area, Volume, Weight, Temperature and Pressure to different unitsBinary Clock - Hours, minutes and seconds have 10 columns each to display timeAutoIt Editor - Code Editor with Syntax Highlighting.Laserix Editor & Player - Create, Edit and Play Laserix LevelsLyric Syncer - Create and use Synchronised Lyrics.Connect 4 - 2 Player Connect 4 Game (Local or Online!, Formatted Chat!!)MD5, SHA-1, SHA-256, Tiger and Whirlpool Hash Finder - Dictionary and Brute Force FindCool Text Client - Create Rendered ImageMy UDF's:GUI Enhance - Enhance your GUIs visually.IDEA File Encryption - Encrypt and decrypt files easily! File Rename - Rename files easilyRC4 Text Encryption - Encrypt text using the RC4 AlgorithmPrime Number - Check if a number is primeString Remove - remove lots of strings at onceProgress Bar - made easySound UDF - Play, Pause, Resume, Seek and Stop.
Link to comment
Share on other sites

  • Moderators

RazerM,

A couple of small problems with the beta.

1. The following section of _SoundOpen does not do what you believe it does:

If $fTryNextMethod And $szExt = ".mp3"  Then
    $sTrackLength = __ReadTLENFromMP3(FileGetShortName($sSndDirName & $sSndFileName))
    If @error Then $fTryNextMethod = True
Else
    $fTryNextMethod = True
EndIf

Even if an mp3 file has read the Xing header successfully, it will pass through the "Else" section and reset $fTryNextMethod. So it will try to read from the properties. If the properties method does not work correctly (on an older version of Windows), and it is a VBR file, you get the incorrect MCI length returned. If you change the section slightly, it resolves the problem:

If $fTryNextMethod Then
    If $szExt = ".mp3"  Then
        $sTrackLength = __ReadTLENFromMP3(FileGetShortName($sSndDirName & $sSndFileName))
        If @error Then $fTryNextMethod = True
    Else
        $fTryNextMethod = True
    EndIf
EndIf

And now the whole section is skipped if the Xing header method found a value.

2. I have discovered a small bug (or feature!) in the ANSI version of AutoIt. I used _HexToString when finding the TLEN length. In my VISTA machine, _HexToString truncates the hex bytes when it meets anything below 0x20. So as the length bytes are terminated by a string of 0x00s it worked without problem. On the ANSI version of AutoIt, _HexToString keeps going, so the string was as long as the tag it was read from and the Number function went "Tilt". I realise this only affects ANSI AutoIT, support for which Jon is about to remove, but as some users might still want to use the Sound UDF, I have come up with the following which works on both versions:

;Instead of this:

$iLengthMs = Number(_HexToString(StringTrimLeft($sTag, StringInStr($sTag, "544C454E") + 21)))

; Use this:
    
$iTemp = StringInStr($sTag, "544C454E") + 21
    
$sTag = StringTrimLeft($sTag, $iTemp)

$sTemp = ""

For $i = 1 To 32 Step 2
    If StringMid($sTag, $i, 2) = "00" Then
        ExitLoop
    Else
        $sTemp &= StringMid($sTag, $i, 2)
    EndIf
Next

$iLengthMs = Number($sTemp)

As written it requires 2 new local variables ($iTemp and $sTemp), so feel free to play with it if you can make it tauter.

Other than these 2 points, the beta works well. And if it had not been for the first, I would never have discovered the second - it was because I got a strange length from a file that I knew had both Xing and TLEN that I started investigating.

A couple of suggestions, if I may:

- Why not read the file once only and then look for Xing and TLEN? At present both these internal functions read the file and CBR files without a Xing header will always have to read twice.

- As future versions of AutoIt will apparently only support later versions of Windows which include the file properties method, why not look to that first and possibly avoid any file reading?

Thanks for the effort,

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

RazerM,

A couple of small problems with the beta.

1. The following section of _SoundOpen does not do what you believe it does:

If $fTryNextMethod And $szExt = ".mp3"  Then
    $sTrackLength = __ReadTLENFromMP3(FileGetShortName($sSndDirName & $sSndFileName))
    If @error Then $fTryNextMethod = True
Else
    $fTryNextMethod = True
EndIf

Even if an mp3 file has read the Xing header successfully, it will pass through the "Else" section and reset $fTryNextMethod. So it will try to read from the properties. If the properties method does not work correctly (on an older version of Windows), and it is a VBR file, you get the incorrect MCI length returned. If you change the section slightly, it resolves the problem:

If $fTryNextMethod Then
    If $szExt = ".mp3"  Then
        $sTrackLength = __ReadTLENFromMP3(FileGetShortName($sSndDirName & $sSndFileName))
        If @error Then $fTryNextMethod = True
    Else
        $fTryNextMethod = True
    EndIf
EndIf

And now the whole section is skipped if the Xing header method found a value.

Thanks, I never thought that through. Will be fixed soon.

2. I have discovered a small bug (or feature!) in the ANSI version of AutoIt. I used _HexToString when finding the TLEN length. In my VISTA machine, _HexToString truncates the hex bytes when it meets anything below 0x20. So as the length bytes are terminated by a string of 0x00s it worked without problem. On the ANSI version of AutoIt, _HexToString keeps going, so the string was as long as the tag it was read from and the Number function went "Tilt". I realise this only affects ANSI AutoIT, support for which Jon is about to remove, but as some users might still want to use the Sound UDF, I have come up with the following which works on both versions:

;Instead of this:

$iLengthMs = Number(_HexToString(StringTrimLeft($sTag, StringInStr($sTag, "544C454E") + 21)))

; Use this:
    
$iTemp = StringInStr($sTag, "544C454E") + 21
    
$sTag = StringTrimLeft($sTag, $iTemp)

$sTemp = ""

For $i = 1 To 32 Step 2
    If StringMid($sTag, $i, 2) = "00" Then
        ExitLoop
    Else
        $sTemp &= StringMid($sTag, $i, 2)
    EndIf
Next

$iLengthMs = Number($sTemp)

As written it requires 2 new local variables ($iTemp and $sTemp), so feel free to play with it if you can make it tauter.

Other than these 2 points, the beta works well. And if it had not been for the first, I would never have discovered the second - it was because I got a strange length from a file that I knew had both Xing and TLEN that I started investigating.

This will also be fixed. I don't entirely understand what is happening here :P, so thanks for the help.

A couple of suggestions, if I may:

- Why not read the file once only and then look for Xing and TLEN? At present both these internal functions read the file and CBR files without a Xing header will always have to read twice.

- As future versions of AutoIt will apparently only support later versions of Windows which include the file properties method, why not look to that first and possibly avoid any file reading?

Thanks for the effort,

M23

1. Yes that makes more sense, I shall change it to pass the file handle into the helper functions.

2. I did this because Xing and TLEN are set especially to cater for this purpose, but it does make more sense with file properties first now that you mention the hit it would have on CBR files.

My Programs:AInstall - Create a standalone installer for your programUnit Converter - Converts Length, Area, Volume, Weight, Temperature and Pressure to different unitsBinary Clock - Hours, minutes and seconds have 10 columns each to display timeAutoIt Editor - Code Editor with Syntax Highlighting.Laserix Editor & Player - Create, Edit and Play Laserix LevelsLyric Syncer - Create and use Synchronised Lyrics.Connect 4 - 2 Player Connect 4 Game (Local or Online!, Formatted Chat!!)MD5, SHA-1, SHA-256, Tiger and Whirlpool Hash Finder - Dictionary and Brute Force FindCool Text Client - Create Rendered ImageMy UDF's:GUI Enhance - Enhance your GUIs visually.IDEA File Encryption - Encrypt and decrypt files easily! File Rename - Rename files easilyRC4 Text Encryption - Encrypt text using the RC4 AlgorithmPrime Number - Check if a number is primeString Remove - remove lots of strings at onceProgress Bar - made easySound UDF - Play, Pause, Resume, Seek and Stop.
Link to comment
Share on other sites

  • Moderators

RazerM,

My apologies for not explaining the TLEN and Xing code better.

1. Xing: The encoder should put an MP3 frame in a VBR file containing the data needed to work out the length of the file. This frame has the following internal structure:

An MP3 header (always 0xFFF, followed by the various bytes as explained in one of my earlier posts)

36 bytes later you find the string "Xing". CBR files either have a similar header containing the string "Info" or nothing. Easiest way to find the string is to search directly.

; Read tag info from file
$file_handle = FileOpen($Passed_File_Name, 4)
$Tag = FileRead($file_handle, 5156)
FileClose($file_handle)

$Xing_Pos = StringInStr($Tag, "58696E67")

Immediately after the "Xing" is a DWord indicating the information to follow. If the 1 bit is set here, the number of frames is present (and I have not yet found a Xing header which does not have this field, because without it there is no point in having the header!). If the field is present, read the DWord to get the frame count.

; Read fields flag
$Flags = Number("0x" & StringMid($Tag, $Xing_Pos + 14, 2))

If BitAND($Flags, 1) = 1 Then
    $Frames = Number("0x" & StringMid($Tag, $Xing_Pos + 16, 8))
Else
    Return 0; No frames field
EndIf

To calculate the length, we use: Length = No of frames * Samples per frame / Sampling freq. The other factors are in the mp3 frame header, so return 36 bytes from the "Xing" string to the frame header itself, read the relevant bytes and calculate the factors.

; Go back to the frame header start
$Mp3_Header = StringMid($Tag, $Xing_Pos - 72, 8)

; Read the relevant bytes
$MPEG_byte =  Number("0x" & StringMid($Mp3_Header, 4, 1))
$Freq_byte =  Number("0x" & StringMid($Mp3_Header, 6, 1))

; Decode the bytes using a couple of Switch blocks

And so calculate the length of the file.

2. TLEN: An ID3v2.3 header is the only version normally placed before the file itself (other versions add to the end so the whole file does not have to be rewritten when tagging). It contains various fields, all denoted by a 4-letter code. The main ones are:

TALB - Album name

TIT2 - Title (there are also TIT1 and TIT3 out of interest!)

TPE1 - Performer or Artist

TRCK - Track number

TCON - Genre

MCDI - CD ID code

and of course TLEN - length in ms.

The ID3v2 header always starts "ID3" followed by the version number (because we need v2.3), so we look for that string:

; Read tag info from file
$file_handle = FileOpen($Passed_File_Name, 4)
$Tag = FileRead($file_handle, 1024)
FileClose($file_handle)

; Check that an ID3v2.3 tag is present
If StringLeft($Tag, 10) <> "0x49443303" Then Return -1

If there is a tag, look for the "TLEN" string within it. Like all tag fields, TLEN has the following structure:

4 bytes - field title (i.e. TLEN)

4 bytes(DWord) - length of the the field (ie offset to next field)

3 bytes - all 0

Field data

so we need to trim the tag to the beginning of the field data:

$temp = StringInStr($Tag, "544C454E")

$Tag = StringTrimLeft($Tag, $temp + 21)

It would be helpful if we could use the field length byte, but some of the fields, and TLEN in particular, have a field length much longer than the actual data (no idea why). Fortunately in the TLEN case, the field is completed by 0x00 bytes, so we have only to read the ASCII numeric bytes and stop at the first 00 byte. This is where the small bug in _HexToString appeared. In Vista it stops automatically when it tries to encode a 0x00 byte - in Win98 it keeps going! So we need a little loop to look for the first 0x00 byte (I thought of just searching for "00" but then realised that the final ASCII byte might be 30). And of course, there are often TLEN fields with no content, just 0x00 bytes (again no idea why):

$temp = ""
For $i = 1 To 32 Step 2
    If StringMid($Tag, $i, 2) = "00" Then
        ExitLoop
    Else
        $temp &= StringMid($Tag, $i, 2)
    EndIf
Next

Now we have the ASCII bytes encoding the length, so convert them to string and then number:

$TLEN = Number(_HexToString($temp))

I hope that is a bit clearer. And if you now want to tighten up the code, please feel free.

For even more detail, I recommend the following websites:

http://www.id3.org/ for the ID3 tags

http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx for the mp3 headers

Right, one last thing. Poking around the MSDN MCI site, I came across the following MCI volume control and wondered if you might consider including it in Sound.au3. I know AutoIt has its own volume control with SoundSetWaveVolume, but I found this function does not work in Win98 whereas the MCI one does. I have written the UDF in the current Sound UDF format so it can use the __mciSendString function:

Func _SoundVolume($aSndID, $iVolume); $Volume: 0(mute) - 1000(full)

;Declare variables
Local $iRet, $vTemp
    If Not IsArray($aSndID) Then
    If Not FileExists($aSndID) Then Return SetError(3, 0, 0); invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0); invalid file/alias

    $iVolume = Int($iVolume)
    If $iVolume < 0 Or $iVolume > 1000 Then Return SetError(2, 0, 0); invalid volume

  ;change volume
    $iRet = __mciSendString("setaudio " & $ aSndID[0] & " volume to "& $iVolume)
    
  ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
    
EndFunc;==>_SoundVolume

I hope the forum holds together long enough to get this finished!

M23

Edited by Melba23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

New beta:

#include <Date.au3>
#include <File.au3>
#include <String.au3>
;===============================================================================
;
; Function Name:   _SoundOpen
; Description::    Opens a sound file for use with other _Sound functions
; Parameter(s):    $sFile - The sound file, $sAlias[optional] - a name such as sound1,
;                  if you do not specify one it is randomly generated
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): string(the sound id) - Success, 0 - Failure
;                  @extended <> 0 - open failed, @error = 2 - File doesn't exist,
;                  @error = 3 - alias contains whitespace
; Author(s):       RazerM, Melba23, some code by Simucal, PsaltyDS
;
;===============================================================================
;
Func _SoundOpen($sFile, $sAlias = "")
    ;Declare variables
    Local $aSndID[3], $sSndID, $iCurrentPos, $iRet, $asAlias, $fTryNextMethod = False, $hFile
    Local $szDrive, $szDir, $szFName, $szExt, $iSndLenMs, $iSndLenMin, $iSndLenHour, $iSndLenSecs, $sSndLenFormat
    Local $sSndDirName, $sSndFileName, $sSndDirShortName, $oShell, $oShellDir, $oShellDirFile, $sRaw, $aInfo
    Local $sTrackLength, $iSoundTicks, $iActualTicks, $iVBRRatio, $aiTime
    
    ;check for file
    If Not FileExists($sFile) Then Return SetError(2, 0, 0)
    ;search for whitespace by character
    $asAlias = StringSplit($sAlias, "")
    For $iCurrentPos = 1 To $asAlias[0]
        If StringIsSpace($asAlias[$iCurrentPos]) Then Return SetError(3, 0, 0)
    Next
    ;create random alias if one is not supplied
    If $sAlias = "" Then
        $sSndID = __RandomStr(10)
    Else
        $sSndID = $sAlias
    EndIf
    
    If StringInStr($sSndID, '!') Then Return SetError(3, 0, 0) ;invalid file/alias
    
    $aSndID[0] = $sSndID
    
    _PathSplit($sFile, $szDrive, $szDir, $szFName, $szExt)

    If $szDrive = "" Then
        $sSndDirName = @WorkingDir & "\" 
    Else
        $sSndDirName = $szDrive & $szDir
    EndIf
    $sSndFileName = $szFName & $szExt

    $sSndDirShortName = FileGetShortName($sSndDirName, 1)

    ;open file
    $iRet = __mciSendString("open " & FileGetShortName($sFile) & " alias " & $aSndID[0])

    $oShell = ObjCreate("shell.application")
    If IsObj($oShell) Then
        $oShellDir = $oShell.NameSpace ($sSndDirShortName)
        If IsObj($oShellDir) Then
            $oShellDirFile = $oShellDir.Parsename ($sSndFileName)
            If IsObj($oShellDirFile) Then
                $sRaw = $oShellDir.GetDetailsOf ($oShellDirFile, -1)
                $aInfo = StringRegExp($sRaw, ": ([0-9]{2}:[0-9]{2}:[0-9]{2})", 3)
                If Not IsArray($aInfo) Then
                    $fTryNextMethod = True
                Else
                    $sTrackLength = $aInfo[0]
                EndIf
            Else
                $fTryNextMethod = True
            EndIf
        Else
            $fTryNextMethod = True
        EndIf
    Else
        $fTryNextMethod = True
    EndIf
    
    If $fTryNextMethod Then
        $fTryNextMethod = False
        If $szExt = ".mp3"  Then
            $hFile = FileOpen(FileGetShortName($sSndDirName & $sSndFileName), 4)
            $sTag = FileRead($hFile, 5156)
            FileClose($hFile)
            $sTrackLength = __ReadXingFromMP3($sTag)
            If @error Then $fTryNextMethod = True
        Else
            $fTryNextMethod = True
        EndIf
    EndIf
    
    If $fTryNextMethod Then
        $fTryNextMethod = False
        If $szExt = ".mp3"  Then
            $sTrackLength = __ReadTLENFromMP3($sTag)
            If @error Then $fTryNextMethod = True
        Else
            $fTryNextMethod = True
        EndIf
    EndIf
    FileClose($hFile)

    If $fTryNextMethod Then
        $fTryNextMethod = False
        ;tell mci to use time in milliseconds
        __mciSendString("set " & $aSndID[0] & " time format miliseconds")
        ;receive length of sound
        $iSndLenMs = __mciSendString("status " & $aSndID[0] & " length", 255)
        
        ;assign modified data to variables
        _TicksToTime($iSndLenMs, $iSndLenHour, $iSndLenMin, $iSndLenSecs)
        
        ;assign formatted data to $sSndLenFormat
        $sTrackLength = StringFormat("%02i:%02i:%02i", $iSndLenHour, $iSndLenMin, $iSndLenSecs)
    EndIf
    
    ; Convert Track_Length to mSec
    $aiTime = StringSplit($sTrackLength, ":")
    $iActualTicks = _TimeToTicks($aiTime[1], $aiTime[2], $aiTime[3])
    
    ;tell mci to use time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    
    ;;Get estimated length
    $iSoundTicks = __mciSendString("status " & $aSndID[0] & " length", 255)

    ;Compare to actual length
    If Abs($iSoundTicks - $iActualTicks) < 1000 Then ;Assume CBR, as our track length from shell.application is only accurate within 1000ms
        $iVBRRatio = 0
    Else ;Set correction ratio for VBR operations
        $iVBRRatio = $iSoundTicks / $iActualTicks
    EndIf
    
    $aSndID[1] = $iVBRRatio
    $aSndID[2] = 0

    Return SetError(0, $iRet, $aSndID)
EndFunc   ;==>_SoundOpen

;===============================================================================
;
; Function Name:   _SoundClose
; Description::    Closes a sound
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundClose($aSndID)
    If Not IsArray($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    If __mciSendString("close " & $aSndID[0]) = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundClose

;===============================================================================
;
; Function Name:   _SoundPlay
; Description::    Plays a sound from the current position (beginning is the default)
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
;                  $fWait - If set to 1 the script will wait for the sound to finish before continuing
;                        - If set to 0 the script will continue while the sound is playing
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 - Failure
;                  @error = 2 - $fWait is invalid, @error = 1 - play failed
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundPlay($aSndID, $fWait = 0)
    ;Declare variables
    Local $iRet, $vTemp
    ;validate $fWait
    If $fWait <> 0 And $fWait <> 1 Then Return SetError(2, 0, 0)
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;if sound has finished, seek to start
    If _SoundPos($aSndID, 2) = _SoundLength($aSndID, 2) Then __mciSendString("seek " & $aSndID[0] & " to start")
    ;If $fWait = 1 then pass wait to mci
    If $fWait = 1 Then
        $iRet = __mciSendString("play " & $aSndID[0] & " wait")
    Else
        $iRet = __mciSendString("play " & $aSndID[0])
    EndIf
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundPlay

;===============================================================================
;
; Function Name: _SoundStop
; Description::    Stops the sound
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundStop($aSndID)
    ;Declare variables
    Local $iRet, $iRet2, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;seek to start
    $iRet = __mciSendString("seek " & $aSndID[0] & " to start")
    ;stop
    $iRet2 = __mciSendString("stop " & $aSndID[0])
    ;return
    If $iRet = 0 And $iRet2 = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundStop

;===============================================================================
;
; Function Name:   _SoundPause
; Description::    Pauses the sound
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundPause($aSndID)
    ;Declare variables
    Local $iRet, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;pause sound
    $iRet = __mciSendString("pause " & $aSndID[0])
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundPause

;===============================================================================
;
; Function Name:   _SoundResume
; Description::    Resumes the sound after being paused
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundResume($aSndID)
    ;Declare variables
    Local $iRet, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;resume sound
    $iRet = __mciSendString("resume " & $aSndID[0])
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundResume

;===============================================================================
;
; Function Name:   _SoundLength
; Description::    Returns the length of the sound in the format hh:mm:ss
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file,
;                  $iMode = 1 - hh:mm:ss, $iMode = 2 - milliseconds
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): Length of the sound - Success, 0 and @error = 1 - $iMode is invalid
; Author(s):       RazerM, Melba23
; Mofified:        jpm
;
;===============================================================================
;
Func _SoundLength($aSndID, $iMode = 1)
    ;Declare variables
    Local $iSndLenMs, $iSndLenMin, $iSndLenHour, $iSndLenSecs, $sSndLenFormat, $vTemp = ""
    ;validate $iMode
    If $iMode <> 1 And $iMode <> 2 Then Return SetError(1, 0, 0)
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[3]
        $aSndID = _SoundOpen($vTemp)
    EndIf
    
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;tell mci to use time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    ;receive length of sound
    $iSndLenMs = __mciSendString("status " & $aSndID[0] & " length", 255)
    If $aSndID[1] <> 0 Then $iSndLenMs = Round($iSndLenMs / $aSndID[1])
    
    If $vTemp <> "" Then _SoundClose($aSndID) ;if user called _SoundLength with a filename
    
    ;assign modified data to variables
    _TicksToTime($iSndLenMs, $iSndLenHour, $iSndLenMin, $iSndLenSecs)
    
    ;assign formatted data to $sSndLenFormat
    $sSndLenFormat = StringFormat("%02i:%02i:%02i", $iSndLenHour, $iSndLenMin, $iSndLenSecs)
    
    ;return correct variable
    If $iMode = 1 Then Return $sSndLenFormat
    If $iMode = 2 Then Return $iSndLenMs
EndFunc   ;==>_SoundLength

;===============================================================================
;
; Function Name:   _SoundSeek
; Description::    Seeks the sound to a specified time
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen (must NOT be a file), $iHour, $iMin, $iSec
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): 1 - Success, 0 and @error = 1 - Failure,
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundSeek(ByRef $aSndID, $iHour, $iMin, $iSec)
    ;Declare variables
    Local $iMs = 0, $iRet, $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias
    
    ;prepare mci to receive time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    ;modify the $iHour, $iMin and $iSec parameters to be in milliseconds
    ;and add to $iMs
    $iMs += $iSec * 1000
    $iMs += $iMin * 60 * 1000
    $iMs += $iHour * 60 * 60 * 1000
    If $aSndID[1] <> 0 Then
        $aSndID[2] = Round($iMs * $aSndID[1]) - $iMs
        $iMs = Round($iMs * $aSndID[1])
    EndIf
    ; seek sound to time ($iMs)
    $iRet = __mciSendString("seek " & $aSndID[0] & " to " & $iMs)
    If _SoundPos($aSndID, 2) < 0 Then $aSndID[2] = 0
    ;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>_SoundSeek

;===============================================================================
;
; Function Name:   _SoundStatus
; Description::    All devices can return the "not ready", "paused", "playing", and "stopped" values.
;                  Some devices can return the additional "open", "parked", "recording", and "seeking" values.(MSDN)
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): Sound Status
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundStatus($aSndID)
    Local $vTemp
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;return status
    Return __mciSendString("status " & $aSndID[0] & " mode", 255)
EndFunc   ;==>_SoundStatus

;===============================================================================
;
; Function Name:   _SoundPos
; Description::    Returns the current position of the song
; Parameter(s):    $sSndID - Sound ID returned by _SoundOpen or sound file,
;                  $iMode = 1 - hh:mm:ss, $iMode = 2 - milliseconds
; Requirement(s):  AutoIt 3.2 ++
; Return Value(s): Current Position - Success, @error = 1 - $iMode is invalid
; Author(s):       RazerM, Melba23
;
;===============================================================================
;
Func _SoundPos($aSndID, $iMode = 1)
    ;Declare variables
    Local $iSndPosMs, $iSndPosMin, $iSndPosHour, $iSndPosSecs, $sSndPosFormat, $vTemp
    ;validate $iMode
    If $iMode <> 1 And $iMode <> 2 Then Return SetError(1, 0, 0)
    If Not IsArray($aSndID) Then
        If Not FileExists($aSndID) Then Return SetError(3, 0, 0) ; invalid file/alias
        $vTemp = FileGetShortName($aSndID)
        Dim $aSndID[1] = [$vTemp]
    EndIf
    If StringInStr($aSndID[0], '!') Then Return SetError(3, 0, 0) ; invalid file/alias

    ;tell mci to use time in milliseconds
    __mciSendString("set " & $aSndID[0] & " time format miliseconds")
    ;receive position of sound
    $iSndPosMs = __mciSendString("status " & $aSndID[0] & " position", 255)
    If $aSndID[1] <> 0 Then
        $iSndPosMs -= $aSndID[2]
    EndIf
    
    ;modify data and assign to variables
    _TicksToTime($iSndPosMs, $iSndPosHour, $iSndPosMin, $iSndPosSecs)

    ;assign formatted data to $sSndPosFormat
    $sSndPosFormat = StringFormat("%02i:%02i:%02i", $iSndPosHour, $iSndPosMin, $iSndPosSecs)
    ;return correct variable
    If $iMode = 1 Then Return $sSndPosFormat
    If $iMode = 2 Then Return $iSndPosMs
EndFunc   ;==>_SoundPos

;internal functions
Func __mciSendString($string, $iLen = 0)
    Local $iRet
    $iRet = DllCall("winmm.dll", "int", "mciSendStringA", "str", $string, "str", "", "long", $iLen, "long", 0)
    If Not @error Then Return $iRet[2]
EndFunc   ;==>__mciSendString

Func __RandomStr($LEN)
    Local $string
    For $iCurrentPos = 1 To $LEN
        $string &= Chr(Random(97, 122, 1))
    Next
    Return $string
EndFunc   ;==>__RandomStr

;===============================================================================
;
; Function Name:   [private] __ReadTLENFromMP3
; Description::    Used internally within this file, not for general use
; Parameter(s):    $sTag - >= 1024 bytes from 'read raw' mode.
; Requirement(s):  File must be an mp3 AFAIK
; Return Value(s): Sound length (hh:mm:ss) - Success, 0 and @error = 1 - Failure
; Author(s):       Melba23
; Modified:        RazerM
;
;===============================================================================
;
Func __ReadTLENFromMP3($sTag)
    Local $iTemp, $sTemp, $iLengthMs, $iLengthHour, $iLengthMin, $iLengthSecs

    ; Check that an ID3v2.3 tag is present
    If StringLeft($sTag, 10) <> "0x49443303"  Then Return SetError(1, 0, 0)

    $iTemp = StringInStr($sTag, "544C454E") + 21
    $sTag = StringTrimLeft($sTag, $iTemp)
    $sTemp = ""

    For $i = 1 To 32 Step 2
        If StringMid($sTag, $i, 2) = "00"  Then
            ExitLoop
        Else
            $sTemp &= StringMid($sTag, $i, 2)
        EndIf
    Next

    $iLengthMs = Number(_HexToString($sTemp))

    If $iLengthMs > 0 Then
        _TicksToTime($iLengthMs, $iLengthHour, $iLengthMin, $iLengthSecs)
        
        ;Convert to hh:mm:ss and return
        Return StringFormat("%02i:%02i:%02i", $iLengthHour, $iLengthMin, $iLengthSecs)
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc   ;==>__ReadTLENFromMP3

;===============================================================================
;
; Function Name:   [private] __ReadXingFromMP3
; Description::    Used internally within this file, not for general use
; Parameter(s):    $sTag - first 5156 bytes from 'read raw' mode.
; Requirement(s):  File must be an mp3 AFAIK
; Return Value(s): Sound length (hh:mm:ss) - Success, 0 and @error = 1 - Failure
; Author(s):       Melba23
; Modified:        RazerM
;
;===============================================================================
;
Func __ReadXingFromMP3($sTag)
    Local $iXingPos, $iFlags, $iFrames, $sHeader, $iMPEGByte, $iFreqByte, $iMPEGVer, $iLayerNum, $iSamples, $iFreqNum, $iFrequency, $iLengthMs, $iLengthHours, $iLengthMins, $iLengthSecs

    $iXingPos = StringInStr($sTag, "58696E67")
    If $iXingPos = 0 Then Return SetError(1, 0, 0)

    ; Read fields flag
    $iFlags = Number("0x" & StringMid($sTag, $iXingPos + 14, 2))
    If BitAND($iFlags, 1) = 1 Then
        $iFrames = Number("0x" & StringMid($sTag, $iXingPos + 16, 8))
    Else
        Return SetError(1, 0, 0); No frames field
    EndIf

    ; Now to find Samples per frame & Sampling rate
    ; Go back to the frame header start
    $sHeader = StringMid($sTag, $iXingPos - 72, 8)

    ; Read the relevant bytes
    $iMPEGByte = Number("0x" & StringMid($sHeader, 4, 1))
    $iFreqByte = Number("0x" & StringMid($sHeader, 6, 1))

    ; Decode them
    ; 8 = MPEG-1, 0 = MPEG-2
    $iMPEGVer = BitAND($iMPEGByte, 8)
    
    ; 2 = Layer III, 4 = Layer II, 6 = Layer I
    $iLayerNum = BitAND($iMPEGByte, 6)

    Switch $iLayerNum
        Case 6
            $iSamples = 384
        Case 4
            $iSamples = 1152
        Case 2
            Switch $iMPEGVer
                Case 8
                    $iSamples = 1152
                Case 0
                    $iSamples = 576
                Case Else
                    $iSamples = 0
            EndSwitch
        Case Else
            $iSamples = 0
    EndSwitch

    ; If not valid return
    If $iSamples = 0 Then Return SetError(1, 0, 0)

    ; 0 = bit 00, 4 = Bit 01, 8 = Bit 10
    $iFreqNum = BitAND($iFreqByte, 12)
    Switch $iFreqNum
        Case 0
            $iFrequency = 44100
        Case 4
            $iFrequency = 48000
        Case 8
            $iFrequency = 32000
        Case Else
            $iFrequency = 0
    EndSwitch

    ; If not valid return
    If $iFrequency = 0 Then Return SetError(1, 0, 0)

    ; MPEG-2 halves the value
    If $iMPEGVer = 0 Then $iFrequency = $iFrequency / 2

    ; Duration in secs = No of frames * Samples per frame / Sampling freq
    $iLengthMs = Int(($iFrames * $iSamples / $iFrequency) * 1000)

    ; Convert to hh:mm:ss and return
    _TicksToTime($iLengthMs, $iLengthHours, $iLengthMins, $iLengthSecs)

    Return StringFormat("%02i:%02i:%02i", $iLengthHours, $iLengthMins, $iLengthSecs)
EndFunc   ;==>__ReadXingFromMP3

Changes:

  • Changed order of sound-length methods.
  • Optimised routine for TLEN and Xing by only reading in data once.
  • Some bug fixes.

Edit: Updated with a few minor bug fixes outlined by Melba23

Edited by RazerM
My Programs:AInstall - Create a standalone installer for your programUnit Converter - Converts Length, Area, Volume, Weight, Temperature and Pressure to different unitsBinary Clock - Hours, minutes and seconds have 10 columns each to display timeAutoIt Editor - Code Editor with Syntax Highlighting.Laserix Editor & Player - Create, Edit and Play Laserix LevelsLyric Syncer - Create and use Synchronised Lyrics.Connect 4 - 2 Player Connect 4 Game (Local or Online!, Formatted Chat!!)MD5, SHA-1, SHA-256, Tiger and Whirlpool Hash Finder - Dictionary and Brute Force FindCool Text Client - Create Rendered ImageMy UDF's:GUI Enhance - Enhance your GUIs visually.IDEA File Encryption - Encrypt and decrypt files easily! File Rename - Rename files easilyRC4 Text Encryption - Encrypt text using the RC4 AlgorithmPrime Number - Check if a number is primeString Remove - remove lots of strings at onceProgress Bar - made easySound UDF - Play, Pause, Resume, Seek and Stop.
Link to comment
Share on other sites

  • Moderators

ummm, did you ever look at what asbeer450 came up with? just curious..

http://www.autoitscript.com/forum/index.ph...st&id=21742

Hi,

Yes, I have looked at these functions - and very comprehensive they are. However, they are also very complex and perhaps a little OTT if you are only looking to control the volume of your own application.

Using SoundSetWaveVolume works very well in Vista, as long as you only try to control your own application, while the MCI version works well in Win98 as well as Vista (I do not have access to any other OS). These 2 ways to control your own application are simple and small.

The Sound UDF seems to me to be aimed at those who want to write their own application to play music files - the SoundGetSetQuery UDF is more for those who are looking for considerably more control over the Windows volume settings.

Please do not think I am being uncomplimentary to SoundGetSetQuery and its author - far from it. I just feel that its use for controlling the volume in your own application is a bit "sledgehammer to crack a nut"!

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • Moderators

RazerM,

Small bug in the TLEN part of the latest beta.

Line 503: $iLengthMs = Number($sTemp) should read $iLengthMs = Number(_HexToString($sTemp)). Otherwise it is directly converting the ASCII codes into decimal, which gives a rather larger number than the one we are looking for - i.e.: 89897:35:30 in place of 00:04:21!!!

I also feel that the size of the tag used to look for TLEN should be increased. Looking at my son's mp3 library, it sems the ID3 tag can be much larger than those I found in my own collection and, as the use of TLEN is be very much the last opportunity to get a correct VBR timing, I feel we should give it as much of a chance as possible. So I would remove line 486: $sTag = StringLeft($sTag, 1024) and search the whole 5156 byte file read. The added overhead for a single search must be minimal and, if we get to this point, we really need to find the TLEN field!

Other than the small bug above, the latest version looks good so far.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Thanks Melba23, I've updated post #47 with the changes mentioned in the post above.

My Programs:AInstall - Create a standalone installer for your programUnit Converter - Converts Length, Area, Volume, Weight, Temperature and Pressure to different unitsBinary Clock - Hours, minutes and seconds have 10 columns each to display timeAutoIt Editor - Code Editor with Syntax Highlighting.Laserix Editor & Player - Create, Edit and Play Laserix LevelsLyric Syncer - Create and use Synchronised Lyrics.Connect 4 - 2 Player Connect 4 Game (Local or Online!, Formatted Chat!!)MD5, SHA-1, SHA-256, Tiger and Whirlpool Hash Finder - Dictionary and Brute Force FindCool Text Client - Create Rendered ImageMy UDF's:GUI Enhance - Enhance your GUIs visually.IDEA File Encryption - Encrypt and decrypt files easily! File Rename - Rename files easilyRC4 Text Encryption - Encrypt text using the RC4 AlgorithmPrime Number - Check if a number is primeString Remove - remove lots of strings at onceProgress Bar - made easySound UDF - Play, Pause, Resume, Seek and Stop.
Link to comment
Share on other sites

  • Moderators

RazerM,

I have tested the new beta on every mp3 I have, in both Vista (where it uses file properties each time) and Win98 (where it uses a mix of Xing, TLEN and MCI depending on the file) and it has produced the correct duration (disregarding the inherent 1 second tolerance) each time. As far as I am concerned it is good to go.

Did you consider adding the volume function?

Look forward to seeing a new UDF issued soon.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Sounds great.

About the volume function, only vcr and digitalvideo devices 'officially' support the 'setaudio <etc>' command. (from MSDN docs)

Therefore I'm not sure it's good practise to add it in as we are dealing with waveform-audio devices.

I'll submit the sound.au3 for release in next beta, and the volume function can be on hold until we discuss it more.

Edited by RazerM
My Programs:AInstall - Create a standalone installer for your programUnit Converter - Converts Length, Area, Volume, Weight, Temperature and Pressure to different unitsBinary Clock - Hours, minutes and seconds have 10 columns each to display timeAutoIt Editor - Code Editor with Syntax Highlighting.Laserix Editor & Player - Create, Edit and Play Laserix LevelsLyric Syncer - Create and use Synchronised Lyrics.Connect 4 - 2 Player Connect 4 Game (Local or Online!, Formatted Chat!!)MD5, SHA-1, SHA-256, Tiger and Whirlpool Hash Finder - Dictionary and Brute Force FindCool Text Client - Create Rendered ImageMy UDF's:GUI Enhance - Enhance your GUIs visually.IDEA File Encryption - Encrypt and decrypt files easily! File Rename - Rename files easilyRC4 Text Encryption - Encrypt text using the RC4 AlgorithmPrime Number - Check if a number is primeString Remove - remove lots of strings at onceProgress Bar - made easySound UDF - Play, Pause, Resume, Seek and Stop.
Link to comment
Share on other sites

  • Moderators

RazerM,

Quite understand your concern over the volume code. I was quite surprised myself when it worked! I had been using the SoundGetSetQuery UDF that Volly referred to as volume control in Win98, but I thought I would give the MCI call a chance. I was even more surprised when it worked in Vista, although I intend to use the built-in SoundSetWaveVolume function as standard for the moment.

Fingers crossed that the new Sound UDF is accepted for the next beta release.

It has been a pleasure working with you - hope we can do it again some time.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • 4 weeks later...

Hello, this is good but I replaced this Sound UDF with default AutoIt and now not works this Func for Volume:

Func _SoundVolume($sSnd_id, $Volume); $Volume: 0 - 1000,  1000= normal
;Declare variables
    Local $iRet
    If StringInStr($sSnd_id,'!') Then Return SetError(3, 0, 0); invalid file/alias
    if $Volume < 0 or $Volume > 1000 Then Return SetError(1, 0, 0)
    $iRet = mciSendString("setaudio " & FileGetShortName($sSnd_id) & " volume to "&$Volume)
;return
    If $iRet = 0 Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc;==>_SoundVolume

How to make this to work with ?!

Edit:

Sounds great.

About the volume function, only vcr and digitalvideo devices 'officially' support the 'setaudio <etc>' command. (from MSDN docs)

Therefore I'm not sure it's good practise to add it in as we are dealing with waveform-audio devices.

I'll submit the sound.au3 for release in next beta, and the volume function can be on hold until we discuss it more.

I didn't sew this... Than, when will be volume function finished? ^^ Edited by n3nE

[quote name='dbzfanatic' post='609696' date='Nov 26 2008, 08:46 AM']This is a help forum not a "write this for me" forum.[/quote](Sorry for bad English) :)

Link to comment
Share on other sites

  • 1 month later...
  • Moderators

m_havo,

A number of questions to try and answer yours!

1. Sound first tries to get the duration property from the shell.application object. If you look at the properties of an mp3 file in Explorer, does it give a duration? We know that it does in XP and Vista, and does not in Win98 and Win2k. So I would not expect Win2kServer to work, and perhaps Win2003 Server is also lacking this information. If you could run the following code with both OSes and post the resulting text from the SciTE console, it would confirm the diagnosis:

#NoTrayIcon
#include <Array.au3>
#include <File.au3>

$hDebugFile = FileOpen(@DesktopDir & "\SoundTest.txt", 2)

$sFile = FileOpenDialog("Open MP3 File", @MyDocumentsDir, "MP3 Files (*.mp3)")
If @error Then
    ConsoleWrite("ERR: No File Opened" & @CRLF)
    Exit
EndIf
Local $szDrive, $szDir, $szFName, $szExt;$szExt is ".mp3" anyway
_PathSplit($sFile, $szDrive, $szDir, $szFName, $szExt)

$Dir_Name = $szDrive & $szDir
$File_Name = $szFName & $szExt

$DOS_Dir = FileGetShortName($Dir_Name, 1)

$ShellApp = ObjCreate("shell.application")
If IsObj($ShellApp) Then
    $Dir = $ShellApp.NameSpace ($DOS_Dir)
    If IsObj($Dir) Then
        $File = $Dir.Parsename ($File_Name)
        If IsObj($File) Then
            $sRaw = $Dir.GetDetailsOf ($File, -1)
            ConsoleWrite("RAW--------------------------" & @CRLF & $sRaw & @CRLF & "END--------------------------" & @CRLF)
            $aInfo = StringRegExp($sRaw, "Duration: ([0-9]{2}:[0-9]{2}:[0-9]{2})", 3)
            If Not IsArray($aInfo) Then
                ConsoleWrite("ERR: $aInfo Not Array")
                Exit
            EndIf
            ConsoleWrite("$aInfo = [" & _ArrayToString($aInfo, ",") & "]" & @CRLF)
            $Track_Length = $aInfo[0]
            ConsoleWrite("$Track_Length = '" & $Track_Length & "'" & @CRLF)
        EndIf
    EndIf
EndIf

FileClose($hDebugFile)
MsgBox(262144, "Done", "Thanks for testing.")
Edited by Melba23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • 1 year later...
  • Moderators

Hi all,

A recent thread highlighted a small problem with the soundfiles in the Windows\Media folder in Vista and Win7 when using _SoundPlay with the filename as a parameter.

Basically these files, which all have spaces in their long names (e.g. C:\Windows\Media\Windows Ding.wav) do not have a short name (ie the old 8.3 format) from Vista onwards - a call to FileGetShortName returns the full name. As a result the DLL calls within _SoundPlay are made with a space in the string parameter and so fail. :P

Experimentation has shown that only one call to the relevant DLL will accept spaces - and that is the one used by _SoundOpen. So to play these files with Sound.au3 you need to make a small modification to the _SoundOpen function as follows:

; This line in _SoundOpen (it is line 79 in the latest version):
__SoundMciSendString("open " & FileGetShortName($sFile) & " alias " & $aSndID[0])

; needs to be changed to:
__SoundMciSendString("open """ & $sFile & """ alias " & $aSndID[0])

Now _SoundOpen will open the file despite the spaces in the name and the returned array can be used in all the other _Sound* functions without problem. :blink:

Trac ticket #1707 has been opened to get this fix added to the next release, but if you feel you really need it, you now have the info to do it yourselves.

You can play also these sound files with the built-in SoundPlay command without problem, which given their short duration and the unlikely need to use any of the other _Sound* functions on them , may well be the easiest solution.

Happy to answer any queries to the best of my ability. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • 2 months later...

@Melba23

For Info i'm on xp sp3.

I corrected sound.au3 like you say, but no result !

I have tried with short path _SoundPlay ( "C:\38.mp3", 1 ) and SoundPlay ( "C:\38.mp3", 1 ) but no result too...

Thanks for your advices ! Posted Image

Edited by wakillon

AutoIt 3.3.14.2 X86 - SciTE 3.6.0 - WIN 8.1 X64 - Other Example Scripts

Link to comment
Share on other sites

  • Moderators

wakillon,

The error only occurred on Vista/Win7 as explained in the above post, so as you are on XP there was no need to amend the UDF. But it does no harm to have done so - and the next release will have the modified files anyway! ;)

Once I had gone through all the hoops that Vista demands to get a file into the C:\ root, I can play mp3 files from there quite happily. The fact that you cannot use the built-in SoundPlay either makes me think that the error is not within Sound.au3. :)

However, could you please try and open the troublesome mp3 file with _SoundOpen and let me know what you get in @error and @extended. That will at least give us some idea why you cannot open the file. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...