Recording from mic - what are the new methods? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Jill Zanfer

Recording from mic - what are the new methods?

24 Oct 2017, 00:06

I spent the better of the past day trying to find ways to record up to a 2 minute clip and save it. The methods outlined here are all out of date for windows 8 or 10 https://autohotkey.com/board/topic/4955 ... even-work/

What would be a good way to do this? I currently use my iphone to record notes and thoughts, I can do much more if I have a control that lets me record quickly and then do actions with the recording that I can build including using speech commands to send it to a folder and so on. Main thing now is to even find if anything exists that works with windows 10 to do this task.
Jill Zanfer

Re: Recording from mic - what are the new methods?

24 Oct 2017, 00:25

I found this thread and it seems exactly what I need, does anyone have the files mentioned in that thread? I searched elsewhere but found no other place for the files

https://autohotkey.com/board/topic/3229 ... dia-files/

Is jballi still active?
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: Recording from mic - what are the new methods?

24 Oct 2017, 03:49

Here is a mci.ahk ,why are you not using the windows voice recorder?
Here is a link to recording using bass.dll you only have to set the correct device ,i do not have a microphone so cannot test it.
https://autohotkey.com/boards/viewtopic.php?t=34352

Code: Select all

/*
Title: MCI Library v1.1

Group: Overview

    This library gives the AutoHotkey developer access to the the Media Control
    Interface (MCI) which provides standard commands for playing/controlling
    multimedia devices.

Group: Notes

Devices Referenced Within The Documentation:

    (start code)
    Driver      Type            Description
    ------      ----            -----------
    MCIAVI      avivideo
    MCICDA      cdaudio         CD audio
                dat             Digital-audio tape player
                digitalvideo    Digital video in a window (not GDI-based)
                MPEGVideo       General-purpose media player
                other           Undefined MCI device
                overlay         Overlay device (analog video in a window)
                scanner         Image scanner
    MCISEQ      sequencer       MIDI sequencer
                vcr             Video-cassette recorder or player
    MCIPIONR    videodisc       Videodisc (Pioneer LaserDisc)
    MCIWAVE     waveaudio       Audio device that plays digitized waveform files
    (end)

MCI Installation:

    To see a list of MCI devices that have been registered for the computer, go
    to the following registry locations...

    (start code)
    Windows NT4/2000/XP/2003/Vista/7/etc.:

      16-bit:
        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI

      32-bit:
        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI32


    Windows 95/98/ME:

        HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\MediaResources\MCI
    (end)

    To see a list of registered file extensions and the MCI device that has been
    assigned to each extension, go the following locations...

        (start code)
        For Windows NT4/2000/XP/2003/Vista/7/etc., this information is stored in
        the following registry location:

            HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions

        For Windows 95/98/ME, this information is stored in the %windir%\win.ini
        file in the "MCI Extensions" section.
        (end)

Performance:

    AutoHotkey automatically loads winmm.dll into memory.  There is no need or
    advantage to preload this library in order to use the MCI library.

Debugging:

    *OutputDebug* statements in the core of some of the functions that only
    execute on condition are permanent and are provided to help the developer
    find and eliminate errors.

Group: Links

    MCI Reference Guide
    - <http://msdn.microsoft.com/en-us/library/ms709461(VS.85).aspx>

Group: Credit

    The MCI library is an offshoot of the Sound_* and Media_* libraries provided
    by *Fincs*.

     -  <http://www.autohotkey.com/forum/viewtopic.php?t=20666>
     -  <http://www.autohotkey.com/forum/viewtopic.php?t=22662>

    Credit and thanks to *Fincs* for creating and enhancing  these libraries
    which are a conversion from the AutoIt "Sound.au3" standard library
    and to *RazerM* for providing the original "Sound.au3" library.

    Notify idea and code from *Sean*
        - <http://www.autohotkey.com/forum/viewtopic.php?p=132331#132331>

    mciGetErrorString call from *PhiLho*
        - <http://www.autohotkey.com/forum/viewtopic.php?p=116011#116011>

Group: Functions
*/


;-----------------------------
;
; Function: MCI_Close
;
; Description:
;
;   Closes the device and any associated resources.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   For most MCI devices, closing a device usually stops playback but not
;   always.  If unsure of the device, consider stopping the device before
;   closing it.
;
;------------------------------------------------------------------------------
MCI_Close(p_lpszDeviceID)
    {
    Static MM_MCINOTIFY:=0x03B9

    ;-- Close device
    l_Return:=MCI_SendString("close " . p_lpszDeviceID . " wait")

    ;-- Turn off monitoring of MM_MCINOTIFY message?
    if OnMessage(MM_MCINOTIFY)="MCI_Notify"
        {
        ;-- Don't process unless all MCI devices are closed
        MCI_SendString("sysinfo all quantity open",l_OpenMCIDevices)
        if (l_OpenMCIDevices=0)
            ;-- Disable monitoring
            OnMessage(MM_MCINOTIFY,"")
        }

    Return l_Return
    }


;-----------------------------
;
; Function: MCI_CurrentTrack
;
; Description:
;
;   Identifies the current track.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The current track. Note: The MCISEQ sequencer returns 1.
;
;------------------------------------------------------------------------------
MCI_CurrentTrack(p_lpszDeviceID)
    {
    MCI_SendString("status " . p_lpszDeviceID . " current track",l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_DeviceType
;
; Description:
;
;   Identifies the device type name.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   A device type name, which can be one of the following...
;
;       (start code)
;       cdaudio
;       dat
;       digitalvideo
;       other
;       overlay
;       scanner
;       sequencer
;       vcr
;       videodisc
;       waveaudio
;       (end)
;
;------------------------------------------------------------------------------
MCI_DeviceType(p_lpszDeviceID)
    {
    MCI_SendString("capability " . p_lpszDeviceID . " device type",l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_Open
;
; Description:
;
;   Opens an MCI device and loads the specified file.
;
; Parameters:
;
;   p_MediaFile - A multimedia file.
;
;   p_Alias - Alias. A name such as media1. [Optional] If blank (the default),
;       an alias will automatically be generated.
;
;   p_Flags - Flags that determine how the device is opened. [Optional]
;
;   Flag Notes:
;   Some commonly used flags include...
;
;       (start code)
;       type {device_type}
;       sharable
;       (end)
;
;   If more than one flag is used, separate each flag/value with a space.
;   For example:
;
;       (start code)
;       type MPEGVideo sharable
;       (end)
;
;   Additional notes...
;
;     - The "wait" flag is automatically added to the end of the command string.
;       This flag directs the device to complete the "open" request before
;       returning.
;
;     - Use the "shareable" flag with care.  Per msdn, the "shareable" flag
;       "initializes the device or file as shareable. Subsequent attempts to
;       open the device or file fail unless you specify "shareable" in both the
;       original and subsequent open commands.  MCI returns an invalid device
;       error if the device is already open and not shareable.  The MCISEQ
;       sequencer and MCIWAVE devices do not support shared files."
;
;     - By default, the MCI device that is opened is determined by the file's
;       extension.  The "type" flag can be used to  1) override the default
;       device that is registered for the file extension or to  2) open a media
;       file with a file extension that is not registered as a MCI file
;       extension.  See the <Notes> section for more information.
;
;     - For a complete list of flags and descriptions for the "open" command
;       string, see the "MCI Reference Guide" in the <Links> section.
;
; Returns:
;
;   The multimedia handle (alias) or 0 (FALSE) to indicate failure.  Failure
;   will occur with any of the following conditions:
;
;    -  The media file does not exist.
;
;    -  The media file's extension is not a regisitered MCI extension.  Note:
;       This test is only performed if the "type" flag is not specified.
;
;    -  Non-zero return code from the <MCI_SendString> function.
;
; Remarks:
;
;   -   Use the <MCI_OpenCDAudio> function to open a CDAudio device.
;
;   -   After the device has been successfully opened, the time format is set to
;       milliseconds which it will remain in effect until it is manually set to
;       another value or until the device is closed.
;
;------------------------------------------------------------------------------
MCI_Open(p_MediaFile,p_Alias="",p_Flags="")
    {
    Static s_Seq:=0

    ;[==============]
    ;[  Parameters  ]
    ;[==============]
    ;-- p_MediaFile
    if (p_MediaFile<>"new")
        {
        ;-- Media file exist?
        IfNotExist %p_MediaFile%
            {
            outputdebug,
               (ltrim join`s
                End Func: %A_ThisFunc%: The media file can't be
                found.  Return=0
               )

            Return False
            }

        ;-- "Type" flag not defined?
        if InStr(A_Space . p_Flags . A_Space," type ")=0
            {
            ;-- Registered file extension?
            SplitPath p_MediaFile,,,l_Extension

            ;-- Which OS type?
            if (A_OSType="WIN32_NT")  ;-- Windows NT4/2000/XP/2003/Vista/7/etc.
                RegRead
                    ,l_Dummy
                    ,HKEY_LOCAL_MACHINE
                    ,SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions
                    ,%l_Extension%
             else
                {
                ;-- Windows 95/98/ME
                iniRead l_Value,%A_WinDir%\win.ini,MCI Extensions,%l_Extension%
                if (l_Value="ERROR")
                    ErrorLevel:=1
                }

            ;-- Not found?
            if ErrorLevel
                {
                outputdebug,
                   (ltrim join`s
                    End Func: %A_ThisFunc%: The file extension for this media
                    file is not registered as a valid MCI extension.  Return=0
                   )

                Return False
                }
            }

        ;-- Enclose in DQ
        p_MediaFile="%p_MediaFile%"
        }

    ;-- Alias
    if p_Alias is Space
       {
       s_Seq++
       p_Alias:="MCIFile" . s_Seq
       }

    ;[===============]
    ;[  Open device  ]
    ;[===============]
    l_CmdString:="open "
        . p_MediaFile
        . " alias "
        . p_Alias
        . A_Space
        . p_Flags
        . " wait"

    l_Return:=MCI_SendString(l_CmdString)
    if l_Return
        l_Return:=0
     else
        l_Return:=p_Alias

    ;-- Set time format to milliseconds
    if l_Return
        {
        l_CmdString:="set " . p_Alias . " time format milliseconds wait"
        MCI_SendString(l_CmdString)
        }

    ;-- Return to sender
    Return l_Return
    }


;-----------------------------
;
; Function: MCI_OpenCDAudio
;
; Description:
;
;   Opens a CDAudio device.
;
; Parameters:
;
;   p_Drive - CDROM drive letter. [Optional] If blank (the default), the first
;       CDROM drive found is used.
;
;   p_Alias - Alias.  A name such as media1. [Optional] If blank (the default),
;       an alias will automatically be generated.
;
;   p_CheckForMedia - Check for media. [Optional] The default is TRUE.
;
; Returns:
;
;   The multimedia handle (alias) or 0 to indicate failure.  Failure will occur
;   with any of the following conditions:
;    -  The computer does not have a CDROM drive.
;    -  The specified drive is not CDROM drive.
;    -  Non-zero return code from the <MCI_SendString> function.
;
;   If p_CheckForMedia is TRUE (the default), failure will also occur with
;   any of the following conditions:
;    -  No media was found in the device.
;    -  Media does not contain audio tracks.
;
; Remarks:
;
;   After the device has been successfully opened, the time format is set to
;   milliseconds which will remain in effect until it is manually set to another
;   value or until the device is closed.
;
;------------------------------------------------------------------------------
MCI_OpenCDAudio(p_Drive="",p_Alias="",p_CheckForMedia=True)
    {
    Static s_Seq:=0

    ;-- Parameters
    p_Drive=%p_Drive%  ;-- Autotrim
    p_Drive:=SubStr(p_Drive,1,1)
    if p_Drive is not Alpha
        p_Drive:=""

    ;-- Drive not specified
    if p_Drive is Space
        {
        ;-- Collect list of CDROM drives
        DriveGet l_ListOfCDROMDrives,List,CDROM
        if l_ListOfCDROMDrives is Space
            {
            outputdebug,
               (ltrim join`s
                End Func: %A_ThisFunc%: This PC does not have functioning CDROM
                drive.  Return=0
               )

            Return False
            }

        ;-- Assign the first CDROM drive
        p_Drive:=SubStr(l_ListOfCDROMDrives,1,1)
        }

    ;-- Is this a CDROM drive?
    DriveGet l_DriveType,Type,%p_Drive%:
    if (l_DriveType<>"CDROM")
        {
        outputdebug,
           (ltrim join`s
            End Func: %A_ThisFunc%: The specified drive (%p_Drive%:) is not
            a CDROM drive.  Return=0
           )

        Return False
        }

    ;-- Alias
    if p_Alias is Space
       {
       s_Seq++
       p_Alias:="MCICDAudio" . s_Seq
       }

    ;-- Open device
    l_CmdString:="open " . p_Drive . ": alias " . p_Alias . " type cdaudio shareable wait"
    l_Return:=MCI_SendString(l_CmdString)
    if l_Return
        l_Return:=0
     else
        l_Return:=p_Alias

    ;-- Device is open
    if l_Return
        {
        ;-- Set time format to milliseconds
        l_CmdString:="set " . p_Alias . " time format milliseconds wait"
        MCI_SendString(l_CmdString)

        ;-- Check for media?
        if p_CheckForMedia
            {
            if not MCI_MediaIsPresent(p_Alias)
                {
                MCI_Close(p_Alias)
                outputdebug,
                   (ltrim join`s
                    End Func: %A_ThisFunc%: Media is not present in the
                    specified drive (%p_Drive%:).  Return=0
                   )

                Return False
                }

            ;-- 1st track an audio track?
            if not MCI_TrackIsAudio(p_Alias,1)
                {
                MCI_Close(p_Alias)
                outputdebug,
                   (ltrim join`s
                    End Func: %A_ThisFunc%: Media in drive %p_Drive%: does not
                    contain CD Audio tracks.  Return=0
                   )

                Return False
                }
            }
        }

    Return l_Return
    }


;-----------------------------
;
; Function: MCI_Length
;
; Description:
;
;   Gets the total length of the media in the current time format.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Track - Track number. [Optional] The default is 0 (no track number).
;
; Returns:
;
;   If a track number is not specified (the default), the length of the entire
;   entire media is returned.  If a track number is specified, only the
;   the length of the specified track is returned.
;
;------------------------------------------------------------------------------
MCI_Length(p_lpszDeviceID,p_Track=0)
    {
    ;-- Build command string
    l_CmdString:="status " . p_lpszDeviceID . " length"
    if p_Track
        l_CmdString.=" track " . p_Track

    ;-- Send it!
    MCI_SendString(l_CmdString,l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_MediaIsPresent
;
; Description:
;
;   Checks to see if media is present in the device.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   TRUE if the media is inserted in the device, otherwise FALSE.
;   msdn: Sequencer, video-overlay, digital-video, and waveform-audio devices
;   (always) return TRUE.
;
;------------------------------------------------------------------------------
MCI_MediaIsPresent(p_lpszDeviceID)
    {
    l_RC:=MCI_SendString("status " . p_lpszDeviceID . " media present",l_lpszReturnString)
    if l_RC  ;-- Probably invalid command for the device
        Return False
     else
        Return (l_lpszReturnString="true") ? True:False
    }


;-----------------------------
;
; Function: MCI_Notify
;
; Description:
;
;   (Internal function.  Do not call directly)
;
;   This function has 2 responsibilties...
;
;    1) If called by the <MCI_Play> function, wParam contains the name of the
;       developer-defined function.  This value is assigned to the s_Callback
;       static variable for future use.
;
;    2) When called as a result of MM_MCINOTIFY message, this function will call
;       the developer-defined function (name stored in the s_Callback static
;       variable) sending the MM_MCINOTIFY status flag as the first parameter.
;
; Parameters:
;
;   wParam - Function name or a MM_MCINOTIFY flag.
;
;   MM_MCINOTIFY flag values are as follows...
;
;       (start code)
;       MCI_NOTIFY_SUCCESSFUL:=0x1
;           The conditions initiating the callback function have been met.
;
;       MCI_NOTIFY_SUPERSEDED:=0x2
;           The device received another command with the "notify" flag set and
;           the current conditions for initiating the callback function have
;           been superseded.
;
;       MCI_NOTIFY_ABORTED:=0x4
;           The device received a command that prevented the current conditions
;           for initiating the callback function from being met. If a new
;           command interrupts the current command and  it also requests
;           notification, the device sends this message only and not
;           MCI_NOTIFY_SUPERSEDED.
;
;       MCI_NOTIFY_FAILURE:=0x8
;           A device error occurred while the device was executing the command.
;       (end)
;
;   lParam - lDevID.  This is the identifier of the device initiating the
;       callback function.  This information is only useful if operating more
;       than one MCI device at a time.
;
; Returns:
;
;   Per msdn, returns 0 to indicate a successful call.
;
; Remarks:
;
;   This function does not complete until the call to the developer-defined
;   function has completed.  If a MM_MCINOTIFY message is issued while this
;   function is running, the message will be treated as unmonitored.
;
;------------------------------------------------------------------------------
MCI_Notify(wParam,lParam,msg,hWnd)
    {
;;;;;    Critical
        ;-- This will cause MM_MCINOTIFY messages to be buffered rather than
        ;   discared if this function is still running when another MM_MCINOTIFY
        ;   message is sent.

    Static s_Callback

    ;-- Internal call?
    if lParam is Space
        {
        s_Callback:=wParam
        return
        }

    ;-- Call developer function
    if IsFunc(s_Callback)
        %s_Callback%(wParam)

    Return 0
    }


;-----------------------------
;
; Function: MCI_NumberOfTracks
;
; Description:
;
;   Identifies the number of tracks on the media.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The number of tracks on the media.
;
; Remarks:
;
;   msdn: The MCISEQ and MCIWAVE devices return 1, as do most VCR devices.  The
;   MCIPIONR device does not support this flag.
;
;------------------------------------------------------------------------------
MCI_NumberOfTracks(p_lpszDeviceID)
    {
    MCI_SendString("status " . p_lpszDeviceID . " number of tracks",l_lpszReturnString)
    Return l_lpszReturnString
    }


;----------
;
; Function: MCI_Pause
;
; Description:
;
;   Pauses playback or recording.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   msdn: With the MCICDA, MCISEQ, and MCIPIONR drivers, the pause command works
;   the same as the stop command.
;
;   Observation: For MCISEQ devices, pause works OK for me.
;
;------------------------------------------------------------------------------
MCI_Pause(p_lpszDeviceID)
    {
    Return MCI_SendString("pause " . p_lpszDeviceID . " wait")
    }


;-----------------------------
;
; Function: MCI_Play
;
; Description:
;
;       Starts playing a device.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Flags - Flags that determine how the device is played. [Optional] If
;       blank, no flags are used.
;
;       Flag Notes:
;
;       Some commonly used flags include...
;
;           (start code)
;           from {position}
;           to {position}
;           (end)
;
;       If more than one flag is used, separate each flag/value with a space.
;       For example:
;
;           (start code)
;           from 10144 to 95455
;           (end)
;
;       Additional notes...
;
;        -  With the exception of very short sound files (<300 ms), the "wait"
;           flag is not recommended.  The entire application will be
;           non-responsive while the media is being played.
;
;        - Do not add the "notify" flag unless you plan to have your script trap
;           the MM_MCINOTIFY message outside of this function.  The "notify"
;           flag is automatically added if the p_Callback parameter contains a
;           value.
;
;        -  For a complete list of flags and descriptions for the "play" command
;           string, see the "MCI Reference Guide" in the <Links> section.
;
;   p_Callback - Function name that is called when the MM_MCINOTIFY message is
;       sent. [Optional] If defined, the "notify" flag is automatically added.
;
;       Important:  The syntax of this parameter and the associated function is
;       critical.  If not defined correctly, the script may crash.
;
;       The function must have at least one parameter.  For example...
;
;           (start code)
;           MyNotifyFunction(NotifyFlag)
;           (end)
;
;       Additional parameters are allowed but they must be optional (contain a
;       default value).  For example:
;
;           (start code)
;           MyNotifyFunction(NotifyFlag,FirstCall=False,Parm3="ABC")
;           (end)
;
;       When a notify message is sent, the approriate MM_MCINOTIFY flag is sent
;       to the developer-defined function as the first parameter.  See the
;       <MCI_Notify> function for a description and a list of MM_MCINOTIFY flag
;       values.
;
;   p_hWndCallback - Handle to a callback window if the p_Callback parameter
;       contains a value and/or if the "notify" flag is defined. [Optional]  If
;       undefined but needed, the handle to default Autohotkey window is used.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
;------------------------------------------------------------------------------
MCI_Play(p_lpszDeviceID,p_Flags="",p_Callback="",p_hwndCallback=0)
    {
    Static MM_MCINOTIFY:=0x03B9

    ;-- Build command string
    l_CmdString:="play " . p_lpszDeviceID
    if p_Flags
        l_CmdString.=A_Space . p_Flags

    ;-- Notify
    p_Callback=%p_Callback%  ;-- AutoTrim
    if StrLen(p_Callback)
        {
        l_CmdString.=" notify"

        ;-- Attach p_Callback to MCI_Notify function
        MCI_Notify(p_Callback,"","","")

        ;-- Monitor for MM_MCINOTIFY message
        OnMessage(MM_MCINOTIFY,"MCI_Notify")
            ;-- Note:  If the MM_MCINOTIFY message was monitored elsewhere,
            ;   this statement will override it.
        }

    ;-- Callback handle
    if not p_hwndCallback
        {
        if InStr(A_Space . l_CmdString . A_Space," notify ")
        or StrLen(p_Callback)
            {
            l_DetectHiddenWindows:=A_DetectHiddenWindows
            DetectHiddenWindows On
            Process Exist
            p_hwndCallback:=WinExist("ahk_pid " . ErrorLevel . " ahk_class AutoHotkey")
            DetectHiddenWindows %l_DetectHiddenWindows%
            }
        }

    ;-- Send it!
    Return MCI_SendString(l_CmdString,Dummy,p_hwndCallback)
    }


;-----------------------------
;
; Function: MCI_Position
;
; Description:
;
;   Identifies the current playback or recording position.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Track - Track number. [Optional] The default is 0 (no track number).
;
; Returns:
;
;   The current playback or recording position in the current time format.  If
;   the p_Track parameter contains a non-zero value, the start position of the
;   track relative to entire media is returned.
;
;------------------------------------------------------------------------------
MCI_Position(p_lpszDeviceID,p_Track=0)
    {
    l_CmdString:="status " . p_lpszDeviceID . " position"
    if p_Track
        l_CmdString.=" track " . p_Track

    MCI_SendString(l_CmdString,l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_Record
;
; Description:
;
;   Starts recording.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Flags - Flags that determine how the device operates for recording.
;       [Optional] If blank, no flags are used.
;
;       Flag Notes:
;
;       Some commonly used flags include...
;
;           (start code)
;           from {position}
;           to {position}
;           insert
;           overwrite
;           (end)
;
;       If more than one flag is used, separate each flag/value with a space.
;       For example:
;
;           (start code)
;           overwrite from 18122 to 26427
;           (end)
;
;
;       Additional notes...
;
;        -  The "wait" flag is not recommended.  The entire application will be
;           non-responsive until recording is stopped with a Stop or Pause
;           command.
;
;        -  For a complete list of flags and descriptions for the "record"
;           command string, see the "MCI Reference Guide" in the <Links>
;           section.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   msdn: Recording stops when a Stop or Pause command is issued.  For the
;   MCIWAVE driver, all data recorded after a file is opened is discarded if the
;   file is closed without saving it.
;
; Credit:
;
;   Original function and examples by heresy.
;
;------------------------------------------------------------------------------
MCI_Record(p_lpszDeviceID,p_Flags="")
    {
    Return MCI_SendString("record " . p_lpszDeviceID . A_Space . p_Flags)
    }


;-----------------------------
;
; Function: MCI_Resume
;
; Description:
;
;   Resumes playback or recording after the device has been paused.  See the
;   <MCI_Pause> function for more information.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   msdn: Digital-video, VCR, and waveform-audio devices recognize this command.
;   Although CD audio, MIDI sequencer, and videodisc devices also recognize this
;   command, the MCICDA, MCISEQ, and MCIPIONR device drivers do not support it.
;
; Programming Notes:
;
;   The <MCI_Play> function can sometimes be an alternative to this function.
;   Many devices will begin to play where they were last paused. If the device
;   does not begin playback correctly, try specifying an appropriate "From" and
;   "To" value (if needed) in the p_Flags parameter.
;
;------------------------------------------------------------------------------
MCI_Resume(p_lpszDeviceID)
    {
    Return MCI_SendString("resume " . p_lpszDeviceID . " wait")
    }


;-----------------------------
;
; Function: MCI_Save
;
; Description:
;
;   Saves an MCI file.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_FileName - File name to store a MCI file.  If the file does not exist, a
;       new file will be created.  If the file exists, it will be overwritten.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   This command can overwrite existing files.  Use with care.
;
; Credit:
;
;   Original function and examples by heresy.
;
;------------------------------------------------------------------------------
MCI_Save(p_lpszDeviceID,p_FileName)
    {
    Return MCI_SendString("save " . p_lpszDeviceID . " """ . p_FileName . """")
    }


;-----------------------------
;
; Function: MCI_Seek
;
; Description:
;
;   Move to a specified position.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Position - Position to stop the seek.  Value must be "start", "end",
;           or an integer.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
;------------------------------------------------------------------------------

/*
Usage and Programming notes:

MCI Bug?: For some reason, seek for cdaudio doesn't work correctly on the
first attempt.  Second and susequent attempts work fine.

*/

MCI_Seek(p_lpszDeviceID,p_Position)
    {
    ;-- Get current status
    l_Status:=MCI_Status(p_lpszDeviceID)

    ;-- Adjust p_Position if necessary
    if p_Position not in start,end
        {
        if p_Position is not Number
            p_Position:=0

        p_Position:=Round(p_Position)  ;-- Integer values only

        if (p_Position>MCI_Length(p_lpszDeviceID))
            p_Position:="end"
         else
            if (p_Position<1)
                p_Position:="start"
                    ;-- This is necessary because some devices don't like a "0"
                    ;   position.
        }

    ;-- Seek
    l_CmdString:="seek " . p_lpszDeviceID . " to " . p_Position . " wait"
    l_Return:=MCI_SendString(l_CmdString)

    ;-- Return to mode before seek
    if l_Status in paused,playing
        {
        MCI_Play(p_lpszDeviceID)

        ;-- Re-pause
        if (l_Status="paused")
            MCI_Pause(p_lpszDeviceID)
        }

;;;;;    l_CurrentPos:=MCI_Position(p_lpszDeviceID)
;;;;;    outputdebug After: l_CurrentPos=%l_CurrentPos%

    Return l_Return
    }


;-----------------------------
;
; Function: MCI_SetBass
;
; Description:
;
;   Sets the audio low frequency level.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Factor - Bass factor.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Observations:
;
;   - Factor range appears to be from 0 to ?????.
;   - Most MCI devices do not support this command.
;
;------------------------------------------------------------------------------
MCI_SetBass(p_lpszDeviceID,p_Factor)
    {
    Return MCI_SendString("setaudio " . p_lpszDeviceID . " bass to " . p_Factor)
    }


;----------
;
; Function: MCI_SetTreble
;
; Description:
;
;   Sets the audio high-frequency level.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Factor - Treble factor.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Observations:
;
;   - Factor range appears to be from 0 to ?????.
;   - Most MCI devices do not support this command.
;
;------------------------------------------------------------------------------
MCI_SetTreble(p_lpszDeviceID,p_Factor)
    {
    Return MCI_SendString("setaudio " . p_lpszDeviceID . " treble to " . p_Factor)
    }


;-----------------------------
;
; Function: MCI_SetVolume
;
; Description:
;
;   Sets the average audio volume for both audio channels. If the left and right
;   volumes have been set to different values, then the ratio of left-to-right
;   volume is approximately unchanged.
;
;   Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Factor - Volume factor.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Observations:
;
;   - Factor range appears to be from 0 to 1000.
;   - Most MCI devices do not support this command.
;
;------------------------------------------------------------------------------
MCI_SetVolume(p_lpszDeviceID,p_Factor)
    {
    Return MCI_SendString("setaudio " . p_lpszDeviceID . " volume to " . p_Factor)
    }


;-----------------------------
;
; Function: MCI_Status
;
; Description:
;
;   Identifies the current mode of the device.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The current mode of the device.
;
;   msdn: All devices can return the "not ready", "paused", "playing", and
;   "stopped" values. Some devices can return the additional "open", "parked",
;   "recording", and "seeking" values.
;
;------------------------------------------------------------------------------
MCI_Status(p_lpszDeviceID)
    {
    MCI_SendString("status " . p_lpszDeviceID . " mode",l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_Stop
;
; Description:
;
;   Stops playback or recording.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
; - After close, a "seek to start" is not done because  1) it slows down the
;   stop request and  2) it may be unwanted.  If you need to set the media
;   position back to the beginning after a stop, call the <MCI_Seek> function
;   and set the p_Position parameter to 0.
;
; - For some CD audio devices, the stop command stops playback and resets the
;   current track position to zero.
;
;------------------------------------------------------------------------------
MCI_Stop(p_lpszDeviceID)
    {
    Return MCI_SendString("stop " . p_lpszDeviceID . " wait")
    }


;-----------------------------
;
; Function: MCI_TrackIsAudio
;
; Description:
;
;   Determines if the specified track is an audio track.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Track - Track number. [Optional] The default is 1.
;
; Returns:
;
;   TRUE if the specified track is an audio track, otherwise FALSE.
;
; Remarks:
;
;   This command will only work on a device that supports multiple tracks.
;
;------------------------------------------------------------------------------
MCI_TrackIsAudio(p_lpszDeviceID,p_Track=1)
    {
    if p_Track is not Integer
        p_Track:=1

    l_RC:=MCI_SendString("status " . p_lpszDeviceID . " type track " . p_Track,l_lpszReturnString)
    if l_RC  ;-- Probably invalid command for the device
        Return False
     else
        Return (l_lpszReturnString="audio") ? True:False
    }


;-----------------------------
;
; Function: MCI_ToHHMMSS
;
; Description:
;
;   Converts the specified number of milliseconds to hh:mm:ss format.
;
; Parameters:
;
;   p_ms - Number of milliseconds.
;
;   p_MinimumSize - Minimum size.  [Optional] The default is 4.  This is the
;       minimum size in characters (not significant digits) that is returned.
;       Unless you want a ":" character to show as the leading character, don't
;       set this value to 3 or 6.
;
; Returns:
;
;   The amount of time in hh:mm:ss format with leading zero and ":" characters
;   suppressed unless the length is less than p_MinimumSize. Note:  If the
;   number of hours is greater than 99, the size of hour ("hh") will increase as
;   needed.
;
; Usage Notes:
;
;   To use this function to create separate variables for the number of hours,
;   minutes, and seconds, set the p_MinimumSize parameter to 8 and use simple
;   *SubStr* commands to create these variables.  For example:
;
;       (start code)
;       x:=MCI_ToHHMMSS(NumberOfMilliseconds,8)
;       HH:=SubStr(x,1,2)
;       MM:=SubStr(x,4,2)
;       SS:=SubStr(x,6,2)
;       (end)
;
;   To remove leading zeros from these variables, simply add 0 to the extracted
;   value.  For example:
;
;       (start code)
;       MM:=SubStr(x,4,2)+0
;       (end)
;
; Credit:
;
;   This function is a customized version of an example that was extracted from
;   the AutoHotkey documenation.
;
;------------------------------------------------------------------------------
MCI_ToHHMMSS(p_ms,p_MinimumSize=4)
    {
    ;-- Convert p_ms to whole seconds
    if p_ms is not Number
        l_Seconds:=0
     else
        if (p_ms<0)
            l_Seconds:=0
         else
            l_Seconds:=Floor(p_ms/1000)

    ;-- Initialize and format
    l_Time:=20121212  ;-- Midnight of an arbitrary date
    EnvAdd l_Time,l_Seconds,Seconds
    FormatTime l_mmss,%l_Time%,mm:ss
    l_FormattedTime:="0" . l_Seconds//3600 . ":" . l_mmss
        ;-- Allows support for more than 24 hours.

    ;-- Trim insignificant leading characters
    Loop
        if StrLen(l_FormattedTime)<=p_MinimumSize
            Break
         else
            if SubStr(l_FormattedTime,1,1)="0"
                StringTrimLeft l_FormattedTime,l_FormattedTime,1
             else
                if SubStr(l_FormattedTime,1,1)=":"
                    StringTrimLeft l_FormattedTime,l_FormattedTime,1
                 else
                    Break

    ;-- Return to sender
    Return l_FormattedTime
    }


;-----------------------------
;
; Function: MCI_ToMilliseconds
;
; Description:
;
;   Converts the specified hour, minute and second into a valid milliseconds
;   timestamp.
;
; Parameters:
;
;   Hour, Min, Sec - Position to convert to milliseconds
;
; Returns:
;
;   The specified position converted to milliseconds.
;
;------------------------------------------------------------------------------
MCI_ToMilliseconds(Hour,Min,Sec)
    {
    milli:=Sec*1000
    milli+=(Min*60)*1000
    milli+=(Hour*3600)*1000
    Return milli
    }


;-----------------------------
;
; Function: MCI_SendString
;
; Description:
;
;   This is the primary function that controls MCI operations.  With the
;   exception of formatting functions, all of the functions in this library call
;   this function.
;
; Parameters:
;
;   p_lpszCommand - MCI command string.
;
;   r_lpszReturnString - Variable name that receives return information.
;       [Optional]
;
;   p_hwndCallback - Handle to a callback window if the "notify" flag was
;       specified in the command string.  [Optional] The default is 0 (No
;       callback window).
;
; Returns:
;
;   Two values are returned.
;
;    1) The function returns 0 if successful or an error number otherwise.
;
;    2) If the MCI command string was a request for information, the variable
;       named in the r_lpszReturnString parameter will contain the requested
;       information.
;
; Debugging:
;
;   If a non-zero value is returned from the call to the mciSendString API
;   function, a call to the mciGetErrorString API function is made to convert
;   the error number into a developer-friendly error message.  All of this
;   information is sent to the debugger in an easy-to-read format.
;
;------------------------------------------------------------------------------
MCI_SendString(p_lpszCommand,ByRef r_lpszReturnString="",p_hwndCallback=0)
    {
    ;-- Workaround for AutoHotkey Basic
    PtrType:=A_PtrSize ? "Ptr":"UInt"

    ;-- Send command
    VarSetCapacity(r_lpszReturnString,512,0)
    l_Return:=DllCall("winmm.dll\mciSendString" . (A_IsUnicode ? "W":"A")
                     ,"Str",p_lpszCommand                   ;-- lpszCommand
                     ,"Str",r_lpszReturnString              ;-- lpszReturnString
                     ,"UInt",512                            ;-- cchReturn
                     ,PtrType,p_hwndCallback                ;-- hwndCallback
                     ,"Cdecl Int")                          ;-- Return type

    if ErrorLevel
        MsgBox
            ,262160  ;-- 262160=0 (OK button) + 16 (Error icon) + 262144 (AOT)
            ,%A_ThisFunc% Function Error,
               (ltrim join`s
                Unexpected ErrorLevel from DllCall to the
                "winmm.dll\mciSendString"
                function.  ErrorLevel=%ErrorLevel%  %A_Space%
                `nSee the AutoHotkey documentation (Keyword: DLLCall) for more
                information.  %A_Space%
               )

    ;-- Return code?
    if l_Return
        {
        VarSetCapacity(l_MCIErrorString,2048)
        DllCall("winmm.dll\mciGetErrorString" . (A_IsUnicode ? "W":"A")
               ,"UInt",l_Return                             ;-- MCI error number
               ,"Str",l_MCIErrorString                      ;-- MCI error text
               ,"UInt",2048)

        ;-- This is provided to help debug MCI calls
        outputdebug,
           (ltrim join`s
            End Func: %A_ThisFunc%: Unexpected return code from command string:
            "%p_lpszCommand%"
            `n--------- Return code=%l_Return% - %l_MCIErrorString%
           )
        }

    Return l_Return
    }
Update tested bass.dll code on winXp using its webcam mic , works fine .Here is recorded wav file displayed by Audacity.

Image
Last edited by noname on 24 Oct 2017, 09:09, edited 1 time in total.
Jill Zanfer

Re: Recording from mic - what are the new methods?

24 Oct 2017, 06:01

thank you!,,
noname wrote:Here is a mci.ahk ,why are you not using the windows voice recorder?
Here is a link to recording using bass.dll you only have to set the correct device ,i do not have a microphone so cannot test it.
https://autohotkey.com/boards/viewtopic.php?t=34352

Code: Select all

/*
Title: MCI Library v1.1

Group: Overview

    This library gives the AutoHotkey developer access to the the Media Control
    Interface (MCI) which provides standard commands for playing/controlling
    multimedia devices.

Group: Notes

Devices Referenced Within The Documentation:

    (start code)
    Driver      Type            Description
    ------      ----            -----------
    MCIAVI      avivideo
    MCICDA      cdaudio         CD audio
                dat             Digital-audio tape player
                digitalvideo    Digital video in a window (not GDI-based)
                MPEGVideo       General-purpose media player
                other           Undefined MCI device
                overlay         Overlay device (analog video in a window)
                scanner         Image scanner
    MCISEQ      sequencer       MIDI sequencer
                vcr             Video-cassette recorder or player
    MCIPIONR    videodisc       Videodisc (Pioneer LaserDisc)
    MCIWAVE     waveaudio       Audio device that plays digitized waveform files
    (end)

MCI Installation:

    To see a list of MCI devices that have been registered for the computer, go
    to the following registry locations...

    (start code)
    Windows NT4/2000/XP/2003/Vista/7/etc.:

      16-bit:
        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI

      32-bit:
        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI32


    Windows 95/98/ME:

        HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\MediaResources\MCI
    (end)

    To see a list of registered file extensions and the MCI device that has been
    assigned to each extension, go the following locations...

        (start code)
        For Windows NT4/2000/XP/2003/Vista/7/etc., this information is stored in
        the following registry location:

            HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions

        For Windows 95/98/ME, this information is stored in the %windir%\win.ini
        file in the "MCI Extensions" section.
        (end)

Performance:

    AutoHotkey automatically loads winmm.dll into memory.  There is no need or
    advantage to preload this library in order to use the MCI library.

Debugging:

    *OutputDebug* statements in the core of some of the functions that only
    execute on condition are permanent and are provided to help the developer
    find and eliminate errors.

Group: Links

    MCI Reference Guide
    - <http://msdn.microsoft.com/en-us/library/ms709461(VS.85).aspx>

Group: Credit

    The MCI library is an offshoot of the Sound_* and Media_* libraries provided
    by *Fincs*.

     -  <http://www.autohotkey.com/forum/viewtopic.php?t=20666>
     -  <http://www.autohotkey.com/forum/viewtopic.php?t=22662>

    Credit and thanks to *Fincs* for creating and enhancing  these libraries
    which are a conversion from the AutoIt "Sound.au3" standard library
    and to *RazerM* for providing the original "Sound.au3" library.

    Notify idea and code from *Sean*
        - <http://www.autohotkey.com/forum/viewtopic.php?p=132331#132331>

    mciGetErrorString call from *PhiLho*
        - <http://www.autohotkey.com/forum/viewtopic.php?p=116011#116011>

Group: Functions
*/


;-----------------------------
;
; Function: MCI_Close
;
; Description:
;
;   Closes the device and any associated resources.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   For most MCI devices, closing a device usually stops playback but not
;   always.  If unsure of the device, consider stopping the device before
;   closing it.
;
;------------------------------------------------------------------------------
MCI_Close(p_lpszDeviceID)
    {
    Static MM_MCINOTIFY:=0x03B9

    ;-- Close device
    l_Return:=MCI_SendString("close " . p_lpszDeviceID . " wait")

    ;-- Turn off monitoring of MM_MCINOTIFY message?
    if OnMessage(MM_MCINOTIFY)="MCI_Notify"
        {
        ;-- Don't process unless all MCI devices are closed
        MCI_SendString("sysinfo all quantity open",l_OpenMCIDevices)
        if (l_OpenMCIDevices=0)
            ;-- Disable monitoring
            OnMessage(MM_MCINOTIFY,"")
        }

    Return l_Return
    }


;-----------------------------
;
; Function: MCI_CurrentTrack
;
; Description:
;
;   Identifies the current track.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The current track. Note: The MCISEQ sequencer returns 1.
;
;------------------------------------------------------------------------------
MCI_CurrentTrack(p_lpszDeviceID)
    {
    MCI_SendString("status " . p_lpszDeviceID . " current track",l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_DeviceType
;
; Description:
;
;   Identifies the device type name.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   A device type name, which can be one of the following...
;
;       (start code)
;       cdaudio
;       dat
;       digitalvideo
;       other
;       overlay
;       scanner
;       sequencer
;       vcr
;       videodisc
;       waveaudio
;       (end)
;
;------------------------------------------------------------------------------
MCI_DeviceType(p_lpszDeviceID)
    {
    MCI_SendString("capability " . p_lpszDeviceID . " device type",l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_Open
;
; Description:
;
;   Opens an MCI device and loads the specified file.
;
; Parameters:
;
;   p_MediaFile - A multimedia file.
;
;   p_Alias - Alias. A name such as media1. [Optional] If blank (the default),
;       an alias will automatically be generated.
;
;   p_Flags - Flags that determine how the device is opened. [Optional]
;
;   Flag Notes:
;   Some commonly used flags include...
;
;       (start code)
;       type {device_type}
;       sharable
;       (end)
;
;   If more than one flag is used, separate each flag/value with a space.
;   For example:
;
;       (start code)
;       type MPEGVideo sharable
;       (end)
;
;   Additional notes...
;
;     - The "wait" flag is automatically added to the end of the command string.
;       This flag directs the device to complete the "open" request before
;       returning.
;
;     - Use the "shareable" flag with care.  Per msdn, the "shareable" flag
;       "initializes the device or file as shareable. Subsequent attempts to
;       open the device or file fail unless you specify "shareable" in both the
;       original and subsequent open commands.  MCI returns an invalid device
;       error if the device is already open and not shareable.  The MCISEQ
;       sequencer and MCIWAVE devices do not support shared files."
;
;     - By default, the MCI device that is opened is determined by the file's
;       extension.  The "type" flag can be used to  1) override the default
;       device that is registered for the file extension or to  2) open a media
;       file with a file extension that is not registered as a MCI file
;       extension.  See the <Notes> section for more information.
;
;     - For a complete list of flags and descriptions for the "open" command
;       string, see the "MCI Reference Guide" in the <Links> section.
;
; Returns:
;
;   The multimedia handle (alias) or 0 (FALSE) to indicate failure.  Failure
;   will occur with any of the following conditions:
;
;    -  The media file does not exist.
;
;    -  The media file's extension is not a regisitered MCI extension.  Note:
;       This test is only performed if the "type" flag is not specified.
;
;    -  Non-zero return code from the <MCI_SendString> function.
;
; Remarks:
;
;   -   Use the <MCI_OpenCDAudio> function to open a CDAudio device.
;
;   -   After the device has been successfully opened, the time format is set to
;       milliseconds which it will remain in effect until it is manually set to
;       another value or until the device is closed.
;
;------------------------------------------------------------------------------
MCI_Open(p_MediaFile,p_Alias="",p_Flags="")
    {
    Static s_Seq:=0

    ;[==============]
    ;[  Parameters  ]
    ;[==============]
    ;-- p_MediaFile
    if (p_MediaFile<>"new")
        {
        ;-- Media file exist?
        IfNotExist %p_MediaFile%
            {
            outputdebug,
               (ltrim join`s
                End Func: %A_ThisFunc%: The media file can't be
                found.  Return=0
               )

            Return False
            }

        ;-- "Type" flag not defined?
        if InStr(A_Space . p_Flags . A_Space," type ")=0
            {
            ;-- Registered file extension?
            SplitPath p_MediaFile,,,l_Extension

            ;-- Which OS type?
            if (A_OSType="WIN32_NT")  ;-- Windows NT4/2000/XP/2003/Vista/7/etc.
                RegRead
                    ,l_Dummy
                    ,HKEY_LOCAL_MACHINE
                    ,SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions
                    ,%l_Extension%
             else
                {
                ;-- Windows 95/98/ME
                iniRead l_Value,%A_WinDir%\win.ini,MCI Extensions,%l_Extension%
                if (l_Value="ERROR")
                    ErrorLevel:=1
                }

            ;-- Not found?
            if ErrorLevel
                {
                outputdebug,
                   (ltrim join`s
                    End Func: %A_ThisFunc%: The file extension for this media
                    file is not registered as a valid MCI extension.  Return=0
                   )

                Return False
                }
            }

        ;-- Enclose in DQ
        p_MediaFile="%p_MediaFile%"
        }

    ;-- Alias
    if p_Alias is Space
       {
       s_Seq++
       p_Alias:="MCIFile" . s_Seq
       }

    ;[===============]
    ;[  Open device  ]
    ;[===============]
    l_CmdString:="open "
        . p_MediaFile
        . " alias "
        . p_Alias
        . A_Space
        . p_Flags
        . " wait"

    l_Return:=MCI_SendString(l_CmdString)
    if l_Return
        l_Return:=0
     else
        l_Return:=p_Alias

    ;-- Set time format to milliseconds
    if l_Return
        {
        l_CmdString:="set " . p_Alias . " time format milliseconds wait"
        MCI_SendString(l_CmdString)
        }

    ;-- Return to sender
    Return l_Return
    }


;-----------------------------
;
; Function: MCI_OpenCDAudio
;
; Description:
;
;   Opens a CDAudio device.
;
; Parameters:
;
;   p_Drive - CDROM drive letter. [Optional] If blank (the default), the first
;       CDROM drive found is used.
;
;   p_Alias - Alias.  A name such as media1. [Optional] If blank (the default),
;       an alias will automatically be generated.
;
;   p_CheckForMedia - Check for media. [Optional] The default is TRUE.
;
; Returns:
;
;   The multimedia handle (alias) or 0 to indicate failure.  Failure will occur
;   with any of the following conditions:
;    -  The computer does not have a CDROM drive.
;    -  The specified drive is not CDROM drive.
;    -  Non-zero return code from the <MCI_SendString> function.
;
;   If p_CheckForMedia is TRUE (the default), failure will also occur with
;   any of the following conditions:
;    -  No media was found in the device.
;    -  Media does not contain audio tracks.
;
; Remarks:
;
;   After the device has been successfully opened, the time format is set to
;   milliseconds which will remain in effect until it is manually set to another
;   value or until the device is closed.
;
;------------------------------------------------------------------------------
MCI_OpenCDAudio(p_Drive="",p_Alias="",p_CheckForMedia=True)
    {
    Static s_Seq:=0

    ;-- Parameters
    p_Drive=%p_Drive%  ;-- Autotrim
    p_Drive:=SubStr(p_Drive,1,1)
    if p_Drive is not Alpha
        p_Drive:=""

    ;-- Drive not specified
    if p_Drive is Space
        {
        ;-- Collect list of CDROM drives
        DriveGet l_ListOfCDROMDrives,List,CDROM
        if l_ListOfCDROMDrives is Space
            {
            outputdebug,
               (ltrim join`s
                End Func: %A_ThisFunc%: This PC does not have functioning CDROM
                drive.  Return=0
               )

            Return False
            }

        ;-- Assign the first CDROM drive
        p_Drive:=SubStr(l_ListOfCDROMDrives,1,1)
        }

    ;-- Is this a CDROM drive?
    DriveGet l_DriveType,Type,%p_Drive%:
    if (l_DriveType<>"CDROM")
        {
        outputdebug,
           (ltrim join`s
            End Func: %A_ThisFunc%: The specified drive (%p_Drive%:) is not
            a CDROM drive.  Return=0
           )

        Return False
        }

    ;-- Alias
    if p_Alias is Space
       {
       s_Seq++
       p_Alias:="MCICDAudio" . s_Seq
       }

    ;-- Open device
    l_CmdString:="open " . p_Drive . ": alias " . p_Alias . " type cdaudio shareable wait"
    l_Return:=MCI_SendString(l_CmdString)
    if l_Return
        l_Return:=0
     else
        l_Return:=p_Alias

    ;-- Device is open
    if l_Return
        {
        ;-- Set time format to milliseconds
        l_CmdString:="set " . p_Alias . " time format milliseconds wait"
        MCI_SendString(l_CmdString)

        ;-- Check for media?
        if p_CheckForMedia
            {
            if not MCI_MediaIsPresent(p_Alias)
                {
                MCI_Close(p_Alias)
                outputdebug,
                   (ltrim join`s
                    End Func: %A_ThisFunc%: Media is not present in the
                    specified drive (%p_Drive%:).  Return=0
                   )

                Return False
                }

            ;-- 1st track an audio track?
            if not MCI_TrackIsAudio(p_Alias,1)
                {
                MCI_Close(p_Alias)
                outputdebug,
                   (ltrim join`s
                    End Func: %A_ThisFunc%: Media in drive %p_Drive%: does not
                    contain CD Audio tracks.  Return=0
                   )

                Return False
                }
            }
        }

    Return l_Return
    }


;-----------------------------
;
; Function: MCI_Length
;
; Description:
;
;   Gets the total length of the media in the current time format.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Track - Track number. [Optional] The default is 0 (no track number).
;
; Returns:
;
;   If a track number is not specified (the default), the length of the entire
;   entire media is returned.  If a track number is specified, only the
;   the length of the specified track is returned.
;
;------------------------------------------------------------------------------
MCI_Length(p_lpszDeviceID,p_Track=0)
    {
    ;-- Build command string
    l_CmdString:="status " . p_lpszDeviceID . " length"
    if p_Track
        l_CmdString.=" track " . p_Track

    ;-- Send it!
    MCI_SendString(l_CmdString,l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_MediaIsPresent
;
; Description:
;
;   Checks to see if media is present in the device.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   TRUE if the media is inserted in the device, otherwise FALSE.
;   msdn: Sequencer, video-overlay, digital-video, and waveform-audio devices
;   (always) return TRUE.
;
;------------------------------------------------------------------------------
MCI_MediaIsPresent(p_lpszDeviceID)
    {
    l_RC:=MCI_SendString("status " . p_lpszDeviceID . " media present",l_lpszReturnString)
    if l_RC  ;-- Probably invalid command for the device
        Return False
     else
        Return (l_lpszReturnString="true") ? True:False
    }


;-----------------------------
;
; Function: MCI_Notify
;
; Description:
;
;   (Internal function.  Do not call directly)
;
;   This function has 2 responsibilties...
;
;    1) If called by the <MCI_Play> function, wParam contains the name of the
;       developer-defined function.  This value is assigned to the s_Callback
;       static variable for future use.
;
;    2) When called as a result of MM_MCINOTIFY message, this function will call
;       the developer-defined function (name stored in the s_Callback static
;       variable) sending the MM_MCINOTIFY status flag as the first parameter.
;
; Parameters:
;
;   wParam - Function name or a MM_MCINOTIFY flag.
;
;   MM_MCINOTIFY flag values are as follows...
;
;       (start code)
;       MCI_NOTIFY_SUCCESSFUL:=0x1
;           The conditions initiating the callback function have been met.
;
;       MCI_NOTIFY_SUPERSEDED:=0x2
;           The device received another command with the "notify" flag set and
;           the current conditions for initiating the callback function have
;           been superseded.
;
;       MCI_NOTIFY_ABORTED:=0x4
;           The device received a command that prevented the current conditions
;           for initiating the callback function from being met. If a new
;           command interrupts the current command and  it also requests
;           notification, the device sends this message only and not
;           MCI_NOTIFY_SUPERSEDED.
;
;       MCI_NOTIFY_FAILURE:=0x8
;           A device error occurred while the device was executing the command.
;       (end)
;
;   lParam - lDevID.  This is the identifier of the device initiating the
;       callback function.  This information is only useful if operating more
;       than one MCI device at a time.
;
; Returns:
;
;   Per msdn, returns 0 to indicate a successful call.
;
; Remarks:
;
;   This function does not complete until the call to the developer-defined
;   function has completed.  If a MM_MCINOTIFY message is issued while this
;   function is running, the message will be treated as unmonitored.
;
;------------------------------------------------------------------------------
MCI_Notify(wParam,lParam,msg,hWnd)
    {
;;;;;    Critical
        ;-- This will cause MM_MCINOTIFY messages to be buffered rather than
        ;   discared if this function is still running when another MM_MCINOTIFY
        ;   message is sent.

    Static s_Callback

    ;-- Internal call?
    if lParam is Space
        {
        s_Callback:=wParam
        return
        }

    ;-- Call developer function
    if IsFunc(s_Callback)
        %s_Callback%(wParam)

    Return 0
    }


;-----------------------------
;
; Function: MCI_NumberOfTracks
;
; Description:
;
;   Identifies the number of tracks on the media.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The number of tracks on the media.
;
; Remarks:
;
;   msdn: The MCISEQ and MCIWAVE devices return 1, as do most VCR devices.  The
;   MCIPIONR device does not support this flag.
;
;------------------------------------------------------------------------------
MCI_NumberOfTracks(p_lpszDeviceID)
    {
    MCI_SendString("status " . p_lpszDeviceID . " number of tracks",l_lpszReturnString)
    Return l_lpszReturnString
    }


;----------
;
; Function: MCI_Pause
;
; Description:
;
;   Pauses playback or recording.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   msdn: With the MCICDA, MCISEQ, and MCIPIONR drivers, the pause command works
;   the same as the stop command.
;
;   Observation: For MCISEQ devices, pause works OK for me.
;
;------------------------------------------------------------------------------
MCI_Pause(p_lpszDeviceID)
    {
    Return MCI_SendString("pause " . p_lpszDeviceID . " wait")
    }


;-----------------------------
;
; Function: MCI_Play
;
; Description:
;
;       Starts playing a device.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Flags - Flags that determine how the device is played. [Optional] If
;       blank, no flags are used.
;
;       Flag Notes:
;
;       Some commonly used flags include...
;
;           (start code)
;           from {position}
;           to {position}
;           (end)
;
;       If more than one flag is used, separate each flag/value with a space.
;       For example:
;
;           (start code)
;           from 10144 to 95455
;           (end)
;
;       Additional notes...
;
;        -  With the exception of very short sound files (<300 ms), the "wait"
;           flag is not recommended.  The entire application will be
;           non-responsive while the media is being played.
;
;        - Do not add the "notify" flag unless you plan to have your script trap
;           the MM_MCINOTIFY message outside of this function.  The "notify"
;           flag is automatically added if the p_Callback parameter contains a
;           value.
;
;        -  For a complete list of flags and descriptions for the "play" command
;           string, see the "MCI Reference Guide" in the <Links> section.
;
;   p_Callback - Function name that is called when the MM_MCINOTIFY message is
;       sent. [Optional] If defined, the "notify" flag is automatically added.
;
;       Important:  The syntax of this parameter and the associated function is
;       critical.  If not defined correctly, the script may crash.
;
;       The function must have at least one parameter.  For example...
;
;           (start code)
;           MyNotifyFunction(NotifyFlag)
;           (end)
;
;       Additional parameters are allowed but they must be optional (contain a
;       default value).  For example:
;
;           (start code)
;           MyNotifyFunction(NotifyFlag,FirstCall=False,Parm3="ABC")
;           (end)
;
;       When a notify message is sent, the approriate MM_MCINOTIFY flag is sent
;       to the developer-defined function as the first parameter.  See the
;       <MCI_Notify> function for a description and a list of MM_MCINOTIFY flag
;       values.
;
;   p_hWndCallback - Handle to a callback window if the p_Callback parameter
;       contains a value and/or if the "notify" flag is defined. [Optional]  If
;       undefined but needed, the handle to default Autohotkey window is used.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
;------------------------------------------------------------------------------
MCI_Play(p_lpszDeviceID,p_Flags="",p_Callback="",p_hwndCallback=0)
    {
    Static MM_MCINOTIFY:=0x03B9

    ;-- Build command string
    l_CmdString:="play " . p_lpszDeviceID
    if p_Flags
        l_CmdString.=A_Space . p_Flags

    ;-- Notify
    p_Callback=%p_Callback%  ;-- AutoTrim
    if StrLen(p_Callback)
        {
        l_CmdString.=" notify"

        ;-- Attach p_Callback to MCI_Notify function
        MCI_Notify(p_Callback,"","","")

        ;-- Monitor for MM_MCINOTIFY message
        OnMessage(MM_MCINOTIFY,"MCI_Notify")
            ;-- Note:  If the MM_MCINOTIFY message was monitored elsewhere,
            ;   this statement will override it.
        }

    ;-- Callback handle
    if not p_hwndCallback
        {
        if InStr(A_Space . l_CmdString . A_Space," notify ")
        or StrLen(p_Callback)
            {
            l_DetectHiddenWindows:=A_DetectHiddenWindows
            DetectHiddenWindows On
            Process Exist
            p_hwndCallback:=WinExist("ahk_pid " . ErrorLevel . " ahk_class AutoHotkey")
            DetectHiddenWindows %l_DetectHiddenWindows%
            }
        }

    ;-- Send it!
    Return MCI_SendString(l_CmdString,Dummy,p_hwndCallback)
    }


;-----------------------------
;
; Function: MCI_Position
;
; Description:
;
;   Identifies the current playback or recording position.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Track - Track number. [Optional] The default is 0 (no track number).
;
; Returns:
;
;   The current playback or recording position in the current time format.  If
;   the p_Track parameter contains a non-zero value, the start position of the
;   track relative to entire media is returned.
;
;------------------------------------------------------------------------------
MCI_Position(p_lpszDeviceID,p_Track=0)
    {
    l_CmdString:="status " . p_lpszDeviceID . " position"
    if p_Track
        l_CmdString.=" track " . p_Track

    MCI_SendString(l_CmdString,l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_Record
;
; Description:
;
;   Starts recording.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Flags - Flags that determine how the device operates for recording.
;       [Optional] If blank, no flags are used.
;
;       Flag Notes:
;
;       Some commonly used flags include...
;
;           (start code)
;           from {position}
;           to {position}
;           insert
;           overwrite
;           (end)
;
;       If more than one flag is used, separate each flag/value with a space.
;       For example:
;
;           (start code)
;           overwrite from 18122 to 26427
;           (end)
;
;
;       Additional notes...
;
;        -  The "wait" flag is not recommended.  The entire application will be
;           non-responsive until recording is stopped with a Stop or Pause
;           command.
;
;        -  For a complete list of flags and descriptions for the "record"
;           command string, see the "MCI Reference Guide" in the <Links>
;           section.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   msdn: Recording stops when a Stop or Pause command is issued.  For the
;   MCIWAVE driver, all data recorded after a file is opened is discarded if the
;   file is closed without saving it.
;
; Credit:
;
;   Original function and examples by heresy.
;
;------------------------------------------------------------------------------
MCI_Record(p_lpszDeviceID,p_Flags="")
    {
    Return MCI_SendString("record " . p_lpszDeviceID . A_Space . p_Flags)
    }


;-----------------------------
;
; Function: MCI_Resume
;
; Description:
;
;   Resumes playback or recording after the device has been paused.  See the
;   <MCI_Pause> function for more information.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   msdn: Digital-video, VCR, and waveform-audio devices recognize this command.
;   Although CD audio, MIDI sequencer, and videodisc devices also recognize this
;   command, the MCICDA, MCISEQ, and MCIPIONR device drivers do not support it.
;
; Programming Notes:
;
;   The <MCI_Play> function can sometimes be an alternative to this function.
;   Many devices will begin to play where they were last paused. If the device
;   does not begin playback correctly, try specifying an appropriate "From" and
;   "To" value (if needed) in the p_Flags parameter.
;
;------------------------------------------------------------------------------
MCI_Resume(p_lpszDeviceID)
    {
    Return MCI_SendString("resume " . p_lpszDeviceID . " wait")
    }


;-----------------------------
;
; Function: MCI_Save
;
; Description:
;
;   Saves an MCI file.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_FileName - File name to store a MCI file.  If the file does not exist, a
;       new file will be created.  If the file exists, it will be overwritten.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
;   This command can overwrite existing files.  Use with care.
;
; Credit:
;
;   Original function and examples by heresy.
;
;------------------------------------------------------------------------------
MCI_Save(p_lpszDeviceID,p_FileName)
    {
    Return MCI_SendString("save " . p_lpszDeviceID . " """ . p_FileName . """")
    }


;-----------------------------
;
; Function: MCI_Seek
;
; Description:
;
;   Move to a specified position.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Position - Position to stop the seek.  Value must be "start", "end",
;           or an integer.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
;------------------------------------------------------------------------------

/*
Usage and Programming notes:

MCI Bug?: For some reason, seek for cdaudio doesn't work correctly on the
first attempt.  Second and susequent attempts work fine.

*/

MCI_Seek(p_lpszDeviceID,p_Position)
    {
    ;-- Get current status
    l_Status:=MCI_Status(p_lpszDeviceID)

    ;-- Adjust p_Position if necessary
    if p_Position not in start,end
        {
        if p_Position is not Number
            p_Position:=0

        p_Position:=Round(p_Position)  ;-- Integer values only

        if (p_Position>MCI_Length(p_lpszDeviceID))
            p_Position:="end"
         else
            if (p_Position<1)
                p_Position:="start"
                    ;-- This is necessary because some devices don't like a "0"
                    ;   position.
        }

    ;-- Seek
    l_CmdString:="seek " . p_lpszDeviceID . " to " . p_Position . " wait"
    l_Return:=MCI_SendString(l_CmdString)

    ;-- Return to mode before seek
    if l_Status in paused,playing
        {
        MCI_Play(p_lpszDeviceID)

        ;-- Re-pause
        if (l_Status="paused")
            MCI_Pause(p_lpszDeviceID)
        }

;;;;;    l_CurrentPos:=MCI_Position(p_lpszDeviceID)
;;;;;    outputdebug After: l_CurrentPos=%l_CurrentPos%

    Return l_Return
    }


;-----------------------------
;
; Function: MCI_SetBass
;
; Description:
;
;   Sets the audio low frequency level.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Factor - Bass factor.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Observations:
;
;   - Factor range appears to be from 0 to ?????.
;   - Most MCI devices do not support this command.
;
;------------------------------------------------------------------------------
MCI_SetBass(p_lpszDeviceID,p_Factor)
    {
    Return MCI_SendString("setaudio " . p_lpszDeviceID . " bass to " . p_Factor)
    }


;----------
;
; Function: MCI_SetTreble
;
; Description:
;
;   Sets the audio high-frequency level.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Factor - Treble factor.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Observations:
;
;   - Factor range appears to be from 0 to ?????.
;   - Most MCI devices do not support this command.
;
;------------------------------------------------------------------------------
MCI_SetTreble(p_lpszDeviceID,p_Factor)
    {
    Return MCI_SendString("setaudio " . p_lpszDeviceID . " treble to " . p_Factor)
    }


;-----------------------------
;
; Function: MCI_SetVolume
;
; Description:
;
;   Sets the average audio volume for both audio channels. If the left and right
;   volumes have been set to different values, then the ratio of left-to-right
;   volume is approximately unchanged.
;
;   Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Factor - Volume factor.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Observations:
;
;   - Factor range appears to be from 0 to 1000.
;   - Most MCI devices do not support this command.
;
;------------------------------------------------------------------------------
MCI_SetVolume(p_lpszDeviceID,p_Factor)
    {
    Return MCI_SendString("setaudio " . p_lpszDeviceID . " volume to " . p_Factor)
    }


;-----------------------------
;
; Function: MCI_Status
;
; Description:
;
;   Identifies the current mode of the device.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The current mode of the device.
;
;   msdn: All devices can return the "not ready", "paused", "playing", and
;   "stopped" values. Some devices can return the additional "open", "parked",
;   "recording", and "seeking" values.
;
;------------------------------------------------------------------------------
MCI_Status(p_lpszDeviceID)
    {
    MCI_SendString("status " . p_lpszDeviceID . " mode",l_lpszReturnString)
    Return l_lpszReturnString
    }


;-----------------------------
;
; Function: MCI_Stop
;
; Description:
;
;   Stops playback or recording.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
; Returns:
;
;   The return code from the <MCI_SendString> function which is 0 if the command
;   completed successfully.
;
; Remarks:
;
; - After close, a "seek to start" is not done because  1) it slows down the
;   stop request and  2) it may be unwanted.  If you need to set the media
;   position back to the beginning after a stop, call the <MCI_Seek> function
;   and set the p_Position parameter to 0.
;
; - For some CD audio devices, the stop command stops playback and resets the
;   current track position to zero.
;
;------------------------------------------------------------------------------
MCI_Stop(p_lpszDeviceID)
    {
    Return MCI_SendString("stop " . p_lpszDeviceID . " wait")
    }


;-----------------------------
;
; Function: MCI_TrackIsAudio
;
; Description:
;
;   Determines if the specified track is an audio track.
;
; Parameters:
;
;   p_lpszDeviceID - Device name or alias.
;
;   p_Track - Track number. [Optional] The default is 1.
;
; Returns:
;
;   TRUE if the specified track is an audio track, otherwise FALSE.
;
; Remarks:
;
;   This command will only work on a device that supports multiple tracks.
;
;------------------------------------------------------------------------------
MCI_TrackIsAudio(p_lpszDeviceID,p_Track=1)
    {
    if p_Track is not Integer
        p_Track:=1

    l_RC:=MCI_SendString("status " . p_lpszDeviceID . " type track " . p_Track,l_lpszReturnString)
    if l_RC  ;-- Probably invalid command for the device
        Return False
     else
        Return (l_lpszReturnString="audio") ? True:False
    }


;-----------------------------
;
; Function: MCI_ToHHMMSS
;
; Description:
;
;   Converts the specified number of milliseconds to hh:mm:ss format.
;
; Parameters:
;
;   p_ms - Number of milliseconds.
;
;   p_MinimumSize - Minimum size.  [Optional] The default is 4.  This is the
;       minimum size in characters (not significant digits) that is returned.
;       Unless you want a ":" character to show as the leading character, don't
;       set this value to 3 or 6.
;
; Returns:
;
;   The amount of time in hh:mm:ss format with leading zero and ":" characters
;   suppressed unless the length is less than p_MinimumSize. Note:  If the
;   number of hours is greater than 99, the size of hour ("hh") will increase as
;   needed.
;
; Usage Notes:
;
;   To use this function to create separate variables for the number of hours,
;   minutes, and seconds, set the p_MinimumSize parameter to 8 and use simple
;   *SubStr* commands to create these variables.  For example:
;
;       (start code)
;       x:=MCI_ToHHMMSS(NumberOfMilliseconds,8)
;       HH:=SubStr(x,1,2)
;       MM:=SubStr(x,4,2)
;       SS:=SubStr(x,6,2)
;       (end)
;
;   To remove leading zeros from these variables, simply add 0 to the extracted
;   value.  For example:
;
;       (start code)
;       MM:=SubStr(x,4,2)+0
;       (end)
;
; Credit:
;
;   This function is a customized version of an example that was extracted from
;   the AutoHotkey documenation.
;
;------------------------------------------------------------------------------
MCI_ToHHMMSS(p_ms,p_MinimumSize=4)
    {
    ;-- Convert p_ms to whole seconds
    if p_ms is not Number
        l_Seconds:=0
     else
        if (p_ms<0)
            l_Seconds:=0
         else
            l_Seconds:=Floor(p_ms/1000)

    ;-- Initialize and format
    l_Time:=20121212  ;-- Midnight of an arbitrary date
    EnvAdd l_Time,l_Seconds,Seconds
    FormatTime l_mmss,%l_Time%,mm:ss
    l_FormattedTime:="0" . l_Seconds//3600 . ":" . l_mmss
        ;-- Allows support for more than 24 hours.

    ;-- Trim insignificant leading characters
    Loop
        if StrLen(l_FormattedTime)<=p_MinimumSize
            Break
         else
            if SubStr(l_FormattedTime,1,1)="0"
                StringTrimLeft l_FormattedTime,l_FormattedTime,1
             else
                if SubStr(l_FormattedTime,1,1)=":"
                    StringTrimLeft l_FormattedTime,l_FormattedTime,1
                 else
                    Break

    ;-- Return to sender
    Return l_FormattedTime
    }


;-----------------------------
;
; Function: MCI_ToMilliseconds
;
; Description:
;
;   Converts the specified hour, minute and second into a valid milliseconds
;   timestamp.
;
; Parameters:
;
;   Hour, Min, Sec - Position to convert to milliseconds
;
; Returns:
;
;   The specified position converted to milliseconds.
;
;------------------------------------------------------------------------------
MCI_ToMilliseconds(Hour,Min,Sec)
    {
    milli:=Sec*1000
    milli+=(Min*60)*1000
    milli+=(Hour*3600)*1000
    Return milli
    }


;-----------------------------
;
; Function: MCI_SendString
;
; Description:
;
;   This is the primary function that controls MCI operations.  With the
;   exception of formatting functions, all of the functions in this library call
;   this function.
;
; Parameters:
;
;   p_lpszCommand - MCI command string.
;
;   r_lpszReturnString - Variable name that receives return information.
;       [Optional]
;
;   p_hwndCallback - Handle to a callback window if the "notify" flag was
;       specified in the command string.  [Optional] The default is 0 (No
;       callback window).
;
; Returns:
;
;   Two values are returned.
;
;    1) The function returns 0 if successful or an error number otherwise.
;
;    2) If the MCI command string was a request for information, the variable
;       named in the r_lpszReturnString parameter will contain the requested
;       information.
;
; Debugging:
;
;   If a non-zero value is returned from the call to the mciSendString API
;   function, a call to the mciGetErrorString API function is made to convert
;   the error number into a developer-friendly error message.  All of this
;   information is sent to the debugger in an easy-to-read format.
;
;------------------------------------------------------------------------------
MCI_SendString(p_lpszCommand,ByRef r_lpszReturnString="",p_hwndCallback=0)
    {
    ;-- Workaround for AutoHotkey Basic
    PtrType:=A_PtrSize ? "Ptr":"UInt"

    ;-- Send command
    VarSetCapacity(r_lpszReturnString,512,0)
    l_Return:=DllCall("winmm.dll\mciSendString" . (A_IsUnicode ? "W":"A")
                     ,"Str",p_lpszCommand                   ;-- lpszCommand
                     ,"Str",r_lpszReturnString              ;-- lpszReturnString
                     ,"UInt",512                            ;-- cchReturn
                     ,PtrType,p_hwndCallback                ;-- hwndCallback
                     ,"Cdecl Int")                          ;-- Return type

    if ErrorLevel
        MsgBox
            ,262160  ;-- 262160=0 (OK button) + 16 (Error icon) + 262144 (AOT)
            ,%A_ThisFunc% Function Error,
               (ltrim join`s
                Unexpected ErrorLevel from DllCall to the
                "winmm.dll\mciSendString"
                function.  ErrorLevel=%ErrorLevel%  %A_Space%
                `nSee the AutoHotkey documentation (Keyword: DLLCall) for more
                information.  %A_Space%
               )

    ;-- Return code?
    if l_Return
        {
        VarSetCapacity(l_MCIErrorString,2048)
        DllCall("winmm.dll\mciGetErrorString" . (A_IsUnicode ? "W":"A")
               ,"UInt",l_Return                             ;-- MCI error number
               ,"Str",l_MCIErrorString                      ;-- MCI error text
               ,"UInt",2048)

        ;-- This is provided to help debug MCI calls
        outputdebug,
           (ltrim join`s
            End Func: %A_ThisFunc%: Unexpected return code from command string:
            "%p_lpszCommand%"
            `n--------- Return code=%l_Return% - %l_MCIErrorString%
           )
        }

    Return l_Return
    }
User avatar
jballi
Posts: 723
Joined: 29 Sep 2013, 17:34

Re: Recording from mic - what are the new methods?

24 Oct 2017, 16:27

If you are still interested, I've added a link to the MCI v1.1 project in the Collection of lost AHK Scripts & Libraries thread. The project includes the library and several example scripts. You can find the post here.
Jill Zanfer

Re: Recording from mic - what are the new methods?

24 Oct 2017, 16:46

jballi wrote:If you are still interested, I've added a link to the MCI v1.1 project in the Collection of lost AHK Scripts & Libraries thread. The project includes the library and several example scripts. You can find the post here.
WOW thank you, is there any ready script that would record but only voice and make a file. What I mean is, if I start to record a 5 minute clip it will pause when it detects no sound?

Thanks
User avatar
jballi
Posts: 723
Joined: 29 Sep 2013, 17:34

Re: Recording from mic - what are the new methods?

24 Oct 2017, 18:01

Jill Zanfer wrote:is there any ready script that would record but only voice and make a file. What I mean is, if I start to record a 5 minute clip it will pause when it detects no sound?
Thanks
To answer your question: No, there is no ready script (at least for me) that can do this. However, it "sounds" (sorry, had to pun it up) doable.

Just a few thoughts...

The solution would probably require multiple threads. One thread to do the main stuff -- start, stop, pause, resume, save, etc. -- and another thread to check the microphone levels. The threads would communicate with each other through global variables. The primary thread would pause recording when the microphone level goes quiet for a pre-determined amount of time (Ex: 3 seconds) and would resume recording when the microphone became active again. There might be a short gap in the recording if the user abruptly resumed speaking.

These are just my thoughts. I have no earthly idea whether this will work or not but like I said, it sounds doable.
Jill Zanfer

Re: Recording from mic - what are the new methods?

24 Oct 2017, 18:30

Thanks! In python I tested a script like that see deenu's code on this page https://stackoverflow.com/questions/892 ... n/43304429
so im sure its doable in ahk too

jballi wrote:
Jill Zanfer wrote:is there any ready script that would record but only voice and make a file. What I mean is, if I start to record a 5 minute clip it will pause when it detects no sound?
Thanks
To answer your question: No, there is no ready script (at least for me) that can do this. However, it "sounds" (sorry, had to pun it up) doable.

Just a few thoughts...

The solution would probably require multiple threads. One thread to do the main stuff -- start, stop, pause, resume, save, etc. -- and another thread to check the microphone levels. The threads would communicate with each other through global variables. The primary thread would pause recording when the microphone level goes quiet for a pre-determined amount of time (Ex: 3 seconds) and would resume recording when the microphone became active again. There might be a short gap in the recording if the user abruptly resumed speaking.

These are just my thoughts. I have no earthly idea whether this will work or not but like I said, it sounds doable.
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: Recording from mic - what are the new methods?

25 Oct 2017, 11:28

Using the code from: https://autohotkey.com/boards/viewtopic.php?t=34352

You can add level monitoring and when it falls below a certain level just halt the writing to the wav file in the RecordFunction.( add a condition to file.rawwrite(buffer+0,length) )

monitoring the recording level with tooltip :

Code: Select all

level:
  LevelDWord := DllCall("BASS\BASS_ChannelGetLevel", UInt,hrecord)
  leftlevel := LevelDWord & 0xffff
  Rightlevel := (LevelDWord>>16) & 0xffff

  tooltip % Floor(leftlevel*0.04) "     " Floor(Rightlevel*0.04)
Return
Jill Zanfer

Re: Recording from mic - what are the new methods?

25 Oct 2017, 11:53

noname wrote:Using the code from: https://autohotkey.com/boards/viewtopic.php?t=34352

You can add level monitoring and when it falls below a certain level just halt the writing to the wav file in the RecordFunction.( add a condition to file.rawwrite(buffer+0,length) )

monitoring the recording level with tooltip :

Code: Select all

level:
  LevelDWord := DllCall("BASS\BASS_ChannelGetLevel", UInt,hrecord)
  leftlevel := LevelDWord & 0xffff
  Rightlevel := (LevelDWord>>16) & 0xffff

  tooltip % Floor(leftlevel*0.04) "     " Floor(Rightlevel*0.04)
Return
I spent many hours trying to get bass to work, maybe one day ill have the proper skill level;
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: Recording from mic - what are the new methods?

26 Oct 2017, 08:42

Image
Here is the testcode i used ( sorry very messy .....),it works on winXp ( i have a webcam with microphone there) but i cannot test it on win10 as you can see no devices are found which is correct :)

original code : https://autohotkey.com/boards/viewtopic.php?t=34352

You need the correct version of bass.dll if you use ahk 32bit you need the 32bit bass version.

You need to enter the device number in the code if you can find your microphone in the list , it is hardcoded here :

Code: Select all

varsetcapacity(info,16,0)



device:=0

Code: Select all

SetBatchLines, -1
#Persistent
t:=1
Gui, Add, Button, x10 y10 w50 h50 gStartRecord, Start
Gui, Add, Button, xp+60 yp w50 h50 gStopRecord, Stop
Gui, Add, Button, xp+60 yp w50 h50 gpause, pause

Gui, Show, autosize, Untitled GUI
settimer,alert,200
return

GuiClose:
ExitApp

pause:
t:=!t
return

alert:
ToolTip , %t%, 100, 100, 2  ; indicates recording/pause
return


StartRecord:
SetTimer, level,100

Control, Disable, , Start

RecordCallback := RegisterCallback("RecordFunction" )

FileDelete, 0_test.wav

;//// WRITE WAV HEADER /////

file := fileopen("0_test.wav", "rw", CP1252)
file.write("RIFF    ") ; leave space for file size - 8

file.write("WAVEfmt ") ; Wave Container, 'fmt ' chunk, this takes up 8 bytes.

fmt_length = 0
numput(16, fmt_length, "UInt") ; 16 bytes, length of formatchunk in bytes
file.rawwrite(fmt_length, 4)

fmt_type = 0
numput(1,fmt_type, "UShort") ; format, 1 = PCM, linear aka non compressed
file.rawwrite(fmt_type, 2)

fmt_channels = 0
numput(2, fmt_channels, "UShort") ; 2 channels
file.rawwrite(fmt_channels, 2)

fmt_sample_rate = 0
numput(44100, fmt_sample_rate, "UInt") ; 44100 samples per second
file.rawwrite(fmt_sample_rate, 4)

fmt_byte_rate = 0
numput(176400, fmt_byte_rate, "UInt") ; bytes per second, 176400
file.rawwrite(fmt_byte_rate, 4)

fmt_blockalign=0		 
numput(4, fmt_blockalign, "UShort") ; NumChannels * BitsPerSample/8
file.rawwrite(fmt_blockalign, 2)

fmt_bitspersample=0		 
numput(16, fmt_bitspersample, "UShort") ; 16 bit resolution
file.rawwrite(fmt_bitspersample, 2)

file.write("data    ") ; this takes up 8 bytes. leave space to write in the size of data chunk.
datasize = 0

;////// WAV HEADER COMPLETE, MOSTLY ///////




;////// LOAD BASS AND START RECORDING  /////////
DllCall("LoadLibrary","str",A_ScriptDir "\bass.dll")

varsetcapacity(info,16,0)

device:=0

z:=BASS_RecordGetDeviceInfo(device,info)


loop 5
{
z=""
name:=""
z:=BASS_RecordGetDeviceInfo(A_Index-2,info)
name := NumGet(info, 0, "ptr")
driver := NumGet(info, A_PtrSize, "ptr")
flags := NumGet(info, A_PtrSize*2, "UInt")

list .="device = " A_Index-2 "   " StrGet(name, "Utf-8")    "`n"
}
msgbox %list%   

DllCall(A_ScriptDir "\bass.dll\BASS_RecordInit", Int,device)
DllCall(A_ScriptDir "\bass.dll\BASS_ErrorGetCode")
hrecord := DllCall(A_ScriptDir "\bass.dll\BASS_RecordStart", UInt, 44100, UInt, 2, UInt, 0, UInt, RecordCallback, UInt, 0)
if DllCall(A_ScriptDir "\bass.dll\BASS_ErrorGetCode")
msgbox % DllCall(A_ScriptDir "\bass.dll\BASS_ErrorGetCode")
return



level:
  LevelDWord := DllCall("BASS\BASS_ChannelGetLevel", UInt,hrecord)
  leftlevel := LevelDWord & 0xffff
  Rightlevel := (LevelDWord>>16) & 0xffff

  tooltip % Floor(leftlevel*0.04) "     " Floor(Rightlevel*0.04)
Return


StopRecord:
DllCall(A_ScriptDir "\bass.dll\BASS_ChannelStop", UInt,hrecord)

;///// BACK TO HEADER //////
file.seek(40)

data_datasize=0
numput(datasize, data_datasize, "UInt") ; little endian
file.rawwrite(data_datasize, 4)

datasize+=36

file.seek(4)

riff_size=0
numput(datasize, riff_size, "UInt") ; little endian
file.rawwrite(riff_size, 4)

;///// DONE ///////


ExitApp
return

BASS_GetDeviceInfo(device,ByRef info){
	global
	Return DllCall("BASS\BASS_GetDeviceInfo", UInt, device, UInt, &info)
}
BASS_RecordGetDeviceInfo(device,ByRef info){
	global
	Return DllCall("BASS\BASS_RecordGetDeviceInfo", UInt, device, UInt, &info)
}

RecordFunction(handle, buffer, length, user)
{
	global file , t
	global datasize

	
	
if t
{
	file.rawwrite(buffer+0,length)
	datasize += length
}
	return true
}
SpecialGuest
Posts: 26
Joined: 15 May 2016, 07:49

Re: Recording from mic - what are the new methods?  Topic is solved

01 Jan 2018, 12:36

Dear noname,

Is there a stable way to set up an EQ for this script? I've added the one you once made for that Chilltrax ♥ bass-player if i remember well.
I'm glad you enjoyed Chilltrax by the way ☺ Yes that was me.

So I removed the writing to file (not needed for me atm) and made it monitor just the buffer so you can see audio input visually but it tends to crash very regularly..
Like it doesn't stay alive for longer than a few seconds. I'm sure I'm not doing it like you're supposed to as the mad scientist approach tends to blow up sometimes (a lot)!

Anyhow, any help would be greatly appreciated. Especially since I've been struggeling with this for quite some time now as you might remember. (EQ Monitor)

Happy New Year everyone! May 2018 treat you and your loved ones well.
TygerByte
Posts: 96
Joined: 12 Aug 2016, 05:22

Re: Recording from mic - what are the new methods?

01 Jan 2018, 16:00

Thought I would post this other way to show an audio meter for reference. Code was taken from this post https://autohotkey.com/boards/viewtopic.php?t=19078

Code: Select all

#SingleInstance, Force
#include VA.ahk
MeterLength = 20
audiomic := VA_GetDevice("capture")
audioMeter := VA_GetAudioMeter(audiomic)

VA_IAudioMeterInformation_GetMeteringChannelCount(audioMeter, channelCount)

; "The peak value for each channel is recorded over one device
;  period and made available during the subsequent device period."
VA_GetDevicePeriod("capture", devicePeriod)

Loop
{
    ; Get the peak value across all channels.
    VA_IAudioMeterInformation_GetPeakValue(audioMeter, peakValue)    
    meter := MakeMeter(peakValue, MeterLength)

        meter .= "`n" MakeMeter(NumGet(peakValues, A_Index*4-4, "float"), MeterLength)

    ToolTip, %meter%
    Sleep, %deviceperiod%
}

MakeMeter(fraction, size)
{
    global MeterLength
    Loop % fraction*size
        meter .= "|"
    Loop % (1-fraction)*size
        meter .= "."
    meter .= "  " fraction
    return meter
}
The following is a concept I tried for a deaf gamer who needed a visual indicator of when sound played. Can be adapted to run other task such as stopping a recording.
Uses tidbit's Window Effects (WE_) WinShake function which I put in instead of including the whole lib.

Code: Select all

#SingleInstance, Force
#include, VA.ahk
MeterLength = 30

audioMeter := VA_GetAudioMeter()

VA_IAudioMeterInformation_GetMeteringChannelCount(audioMeter, channelCount)

; "The peak value for each channel is recorded over one device
;  period and made available during the subsequent device period."
VA_GetDevicePeriod("capture", devicePeriod)

Loop
{
    ; Get the peak value across all channels.
    VA_IAudioMeterInformation_GetPeakValue(audioMeter, peakValue)    
    meter := MakeMeter(peakValue, MeterLength)
    
    ; Get the peak values of all channels.
    VarSetCapacity(peakValues, channelCount*4)
    VA_IAudioMeterInformation_GetChannelsPeakValues(audioMeter, channelCount, &peakValues)
    Loop %channelCount%
        meter .= "`n" MakeMeter(NumGet(peakValues, A_Index*4-4, "float"), MeterLength)

    ToolTip, %meter%
	if (peakValue > 0.06) 
	{
		gosub, shake
	}
    Sleep, %devicePeriod%
}

MakeMeter(fraction, size)
{
    global MeterLength
    Loop % fraction*size
        meter .= "|"
    Loop % (1-fraction)*size
        meter .= "."
    meter .= "  " fraction
    return meter
}

shake:
WE_WinShake("PVP.net Client", 10, 8, 2)
return

WE_WinShake(WE_window="", WE_shakes=20, WE_xrattle=2, WE_yrattle=3)
    {
    WinGetPos, WE_mywinx,WE_mywiny , , , %WE_window%
    Loop, %WE_shakes%
        {
        Random, WE_rattlex,  WE_mywinx-WE_xrattle,  WE_mywinx+WE_xrattle
        Random, WE_rattley,  WE_mywiny-WE_yrattle,  WE_mywiny+WE_yrattle
        WinMove, %WE_window%,, %WE_rattlex%, %WE_rattley%
        }
    }
SpecialGuest
Posts: 26
Joined: 15 May 2016, 07:49

Re: Recording from mic - what are the new methods?

01 Jan 2018, 16:29

Hi Tygerbyte

Thanks for the swift reply. I actually came from VA before I went to Bass.dll for it's capability of getting a somewhat detailed view on the audio frequencies.

The second script works fine indeed for audio level detection. (the first one fails here)

Yet for me it is quite important to be able to visualize the frequencies separatly and VA is not able to do that from what I know.
AudioLevel.dll from Rainmeter can do it too - like bass.dll - but I have no idea on how to get that to work in AHK.
I clearly lack experience when it comes to working with Dynamic Link Libraries and Calls to those I guess.

Still I'm sure your visual indicator script will come in handy somewhere so thanks for sharing that and great initiative for helping that person out this way.

Cheers
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: Recording from mic - what are the new methods?

04 Jan 2018, 09:11

Unfortunately i do not have a microphone and moved to win10 .It is like fishing in trouble water ........without a worm ....and the lake is frozen......
But i will take a look :)
SpecialGuest
Posts: 26
Joined: 15 May 2016, 07:49

Re: Recording from mic - what are the new methods?

04 Jan 2018, 22:02

Thanks. I might have a solution for the microphone issue 8-)
You can choose the Stereo Mix recording device where all sound output passes through. Just play some music or so.

I've made a compact version using your player and the recording demo you linked. Check it out :
(warning: it crashes often. AHK exit code 3221225477 and 3221226356 or BASS error 5 BASS_ERROR_HANDLE invalid handle, see below)
Spoiler
I've tried many other ways using my VA "EQ" scripts that I converted to Bass but all tend to be unstable when i use the recordingbuffer.
Hope we can figure this one out but with this compact script it should be easier at least, and you know this script already :beer:
I'm betting it will provide a solution for my other experiments as well since the culprit is likely to be the same.

About the error codes :

- The bass invalid handle error just pops up now and then and then goes away. Likely due to one or both of the following.
- The 3221226356 STATUS_HEAP_CORRUPTION error points to writing to unallocated or uninitialized memory causing undefined and unpredicatable behaviour.
- The 3221225477 STATUS_ACCESS_VIOLATION error may point to the handle being lost due to the dll being unloaded after a call, if not loaded as library first.

It could also be due to the good old UInt/UPtr, Int/Ptr and VarSetCapacity mix-ups I suppose :facepalm:
Some info I found from Lexikos regarding those https://autohotkey.com/boards/viewtopic.php?t=13204
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: Recording from mic - what are the new methods?

06 Jan 2018, 09:42

Image
You can choose the Stereo Mix recording device where all sound output passes through. Just play some music or so.
Thanks, that worked to test it and as you found out after a few seconds it crashed.I borrowed a mic and monitored playing mp3.
Maybe not the most "professional" solution but if channelgetdata returns -1 ........ignore it.....and wait for a better one ?

Best of luck.

Code: Select all

SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1

#Include *i gdip_all.ahk   

If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}

Gui, 1:  -Caption +E0x80000 +LastFound +OwnDialogs +Owner +hwndhwnd +alwaysontop
Gui, 1: Show, NA 

w:=270
h:=120

hbm := CreateDIBSection(w,h)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
pGraphics := Gdip_GraphicsFromHDC(hdc)

Gdip_GraphicsClear(pGraphics,0xff202020)
UpdateLayeredWindow(hwnd, hdc,(a_screenwidth-w)//2,(a_screenheight-h)//2,w,h)

gosub ini
settimer,update,50
OnMessage(0x201, "WM_LBUTTONDOWN")
return


ini:
pPen:=Gdip_CreatePen(0xffB803D1, 2)
BASS_Load()
file := fileopen("0_test.wav", "rw", CP1252)
RecordCallback := RegisterCallback("RecordFunction")
DllCall(A_ScriptDir "\bass.dll\BASS_RecordInit", Int,-1)
hrecord := DllCall(A_ScriptDir "\bass.dll\BASS_RecordStart", UInt, 44100, UInt, 2, UInt, 0, UInt, NULL, UInt, 0)
return

update:
LevelDWord := DllCall("BASS\BASS_ChannelGetLevel", UInt,hrecord)
level := LevelDWord & 0xffff "    " (LevelDWord>>16) & 0xffff

Gdip_GraphicsClear(pGraphics, 0xd0000000)
VarSetCapacity(buf,128*4,0)  ;Float = 4 bytes
if !DllCall("BASS\BASS_ChannelGetData", UInt,hrecord, Ptr,&buf,UInt,0x80000000)
return

xpos:=10

Loop 120
  {
  xpos +=2
  t :=110-NumGet(buf,4*(A_Index-1),"Float")*3000
  Gdip_DrawLine(pGraphics, pPen, xpos, t, xpos, t+2)
  }

Options= x5 y5  cffC0C0C0   s12 r4
Gdip_TextToGraphics(pGraphics, "level= " level, Options, "tahoma") 
UpdateLayeredWindow(hwnd, hdc)
return


RecordFunction(handle, buffer, length, user){
return true
}
    

WM_LBUTTONDOWN(wParam,lParam,msg,hwnd){
PostMessage, 0xA1, 2 
}

esc::
exitapp

;endofcode
; Wrapper for bass.dll (2.4.5.0)
; www.autohotkey.com/forum/topic55454.html
; for AHK 1.0.48.05
; by toralf
; Version 0.1 (2010-02-20)
; based on BASS Library	by k3ph

; NEEDS:  bass.dll      www.un4seen

; ################################
; ##  List of public functions  ##
; ################################
; BASS_Load([DLLPath, Device, PlugIns]) ;loads BASS wrapper, must be called before any other function
; BASS_Free()                           ;frees BASS wrapper, must be called at end of script
; BASS_IsPlaying(hStream)               ;returns playback status: 0=Stopped, 1=Playing, 2=Stalled, 3=Paused
; BASS_Play([File])                     ;plays a file or restarts it when paused and no file is specified
;                                         (returns hStream on success, otherwise -1)
; BASS_Stop()                           ;stop playback of file (returns hStream="" on success, otherwise -1)
; BASS_Pause()                          ;toogles pause of playback of file (returns hStream on success, otherwise -1)
; BASS_Volume([Volume])                 ;sets or gets master volume: 0 (silent) to 1 (max)
; BASS_GetDevice(hStream)               ;returns device number, otherwise -1
; BASS_Seconds2Bytes(hStream,SecPos)    ;converts a position from seconds to bytes,
;                                         returns on Error negative value
; BASS_Bytes2Seconds(hStream,BytePos)   ;converts a position from bytes to seconds,
;                                         returns on Error negative value
; BASS_GetLen(hStream)                  ;returns playback length in bytes, returns on Error -1
; BASS_GetPos(hStream)                  ;returns playback position in bytes, returns on Error -1
; BASS_SetPos(hStream,BytePos)          ;sets playback position in bytes, returns 1, otherwise 0
; BASS_GetLevel(hStream, ByRef LeftLevel, ByRef RightLevel) ;returns level (peak amplitude) of a stream, returns on Error -1
; BASS_GetLevel(hStream)                ;returns level (peak amplitude 0-32768) of a stream, returns on Error -1 or 0 when stream is stalled
; BASS_IsSliding(hStream,Attrib)        ;returns 1 if attribute is sliding, otherwise 0,
;                                         Attributes: 1=Freq, 2=Vol, 3=Pan, 4=EAXMix
; BASS_SetSliding(hStream,Attrib,NewValue,TimeMS)   ;set attribute from its current value to slide to new value in time period
; BASS_GetCPU()                         ;returns CPU usage of BASS
; BASS_GetVersion()                     ;returns version of BASS that is loaded
; BASS_ProgressMeter_Add([x, y, Width, Height, Color, Bgcolor, ControlID, GuiID])  ;adds a progress meter to a gui
; BASS_ProgressMeter_Update(hStream [, ControlID, GuiID])   ;updates a progress meter for a stream
; BASS_PluginLoad(File)                 ;loads a plugin of BASS
; BASS_PluginFree([hPlugin])            ;frees a plugin of BASS ("" or 0 = All Plugins)
; BASS_ErrorGetCode()                   ;Return the error message as code and description
;
; #################################
; ##  List of private functions  ##
; #################################
; BASS_InitFree([Modus, DLLPath, Device, Plugins])
; BASS_StreamFileToChannel(Modus [, File])
; BASS_ProgressMeter(GuiID, ControlID, WidthOrhStream, Height [, Color, Bgcolor, X, Y])



BASS_Load(DLLPath="", Device=-1, PlugIns="ALL"){  ;loads BASS wrapper, must be called before any other function
    Return BASS_InitFree("Load", DLLPath, Device, Plugins)
  }
BASS_Free(){                             ;frees BASS wrapper, must be called at end of script
    Return BASS_InitFree("Free")
  }
BASS_InitFree(Modus="", DLLPath="", Device="", Plugins=""){
    static
    DLLName = bass.dll
    If (Modus = "Load"){                             ;load dll to memory
        If (!hBassDll := DllCall("LoadLibrary", Str,DLLPath . DLLName)){
            MsgBox, 48, BASS Error!,
              (Ltrim
                Failed to start %DLLName%
                Please ensure you have %DLLName% in the correct path %DLLPath%
              )
            Return 0
          }
        local Freq=44100,Flags=0,Win=0,Clsid=0         ;initialize output device
        If !DllCall("BASS\BASS_Init", Int,Device, Int,Freq, Int,Flags, UInt,Win, UInt,Clsid){
            ErrorLevel := BASS_ErrorGetCode()
            MsgBox, 48, BASS Error!,
              (Ltrim
                Failed to initialize BASS
                Error: %ErrorLevel%
              )
            Return 0
          }
        ;Load plugins
        PlugIns := PlugIns = "All"
        ? "tags,fx,vfx,enc,mix,vis,vst,wadsp,video,cd,midi,flac,wma,wv,aac,ape,mpc,ac3,alac,spx,tta,ofr"
: PlugIns
  Loop, Parse, PlugIns, `,
      If IsFunc("BASS_" A_LoopField "_Load")
          BASS_%A_LoopField%_Load(DLLPath)
      }Else If (Modus = "Free"){
          If !BASS_PluginFree()                          ;free all Plugins
              MsgBox, 48, BASS Error!, Failed to free all plugins.`nError: %ErrorLevel%
          DllCall("BASS\BASS_Free")                      ;free all resources used by the output device
          DllCall("FreeLibrary", UInt,hBassDll)          ;free dll from memory
        }
Return 1
}

BASS_IsPlaying(hStream){ ;returns playback status: 0=Stopped, 1=Playing, 2=Stalled, 3=Paused
    ;BASS_ChannelIsActive return values
    ; BASS_ACTIVE_STOPPED := 0 ;
    ; BASS_ACTIVE_PLAYING := 1 ;
    ; BASS_ACTIVE_STALLED := 2 ; Playback of the stream has been stalled due to a lack of sample data. The playback will automatically resume once there is sufficient data to do so.
    ; BASS_ACTIVE_PAUSED  := 3 ;
    Return DllCall("BASS\BASS_ChannelIsActive", UInt,hStream)
  }

BASS_Play(File=""){  ;plays a file or restarts it when paused and no file is specified (returns hStream on success, otherwise -1)
    Return BASS_StreamFileToChannel("Play",File)
  }
BASS_Stop(){         ;stop playback of file (returns hStream="" on success, otherwise -1)
    Return BASS_StreamFileToChannel("Stop")
  }
BASS_Pause(){        ;toogles pause of playback of file (returns hStream on success, otherwise -1)
    Return BASS_StreamFileToChannel("Pause")
  }
BASS_StreamFileToChannel(Modus,File=""){
    static
    If (File AND !FileExist(File)){     ;Check if file Exists when specified
        MsgBox, 48, BASS Error!,
          (Ltrim
            File does not exist:
            %File%
          )
        ;Return -1
      }
    If (Modus = "Play" And File){        ;play file from beginning
        If !(hStream := DllCall("BASS\BASS_StreamCreateFile", UInt,FromMem:=0
                  , UInt,&File, UInt64,Offset:=0, UInt64,Length:=0
                  , UInt,(A_IsUnicode ? 0x80000000 : 0x40000))){
            ErrorLevel := BASS_ErrorGetCode()
        MsgBox, 48, BASS Error!,
          (Ltrim
            Failed to create a stream from file:
            %File%
            Error: %ErrorLevel%
          )
        Return -1
      }
    If !DllCall("BASS\BASS_ChannelPlay", UInt,hStream, Int,Restart:=1){
        ErrorLevel := BASS_ErrorGetCode()
        MsgBox, 48, BASS Error!,
          (Ltrim
            Failed to play stream from file:
            %File%
            Error: %ErrorLevel%
          )
        Return -1
      }
}Else If (Modus = "Play" And !File And hStream){   ;restart playback (when Paused)
    If !DllCall("BASS\BASS_ChannelPlay", UInt,hStream, Int,Restart:=0){
        ErrorLevel := BASS_ErrorGetCode()
        MsgBox, 48, BASS Error!,
          (Ltrim
            Failed to restart stream from file:
            %File%
            Error: %ErrorLevel%
          )
        Return -1
      }
}Else If (Modus = "Stop" And hStream){             ;stop playback
    If BASS_IsPlaying(hStream)
        If !DllCall("BASS\BASS_ChannelStop", UInt,hStream){
            ErrorLevel := BASS_ErrorGetCode()
            MsgBox, 48, BASS Error!,
              (Ltrim
                Failed to stop stream from file:
                %File%
                Error: %ErrorLevel%
              )
            Return -1
          }
    hStream =                                        ;clear hStream
}Else If (Modus = "Pause" And hStream){            ;toogle Pause of playback
    local IsPlaying
    IsPlaying := BASS_IsPlaying(hStream)               ;get Status
    If (IsPlaying = 3)                                    ;stream is Paused
        hStream := BASS_Play()                                 ;restart playback
    Else If (IsPlaying = 1){                              ;stream is playing
        If !DllCall("BASS\BASS_ChannelPause", UInt,hStream){   ;Pause playback
            ErrorLevel := BASS_ErrorGetCode()
            MsgBox, 48, BASS Error!,
              (Ltrim
                Failed to pause stream from file:
                %File%
                Error: %ErrorLevel%
              )
            Return -1
          }
      }
  }
Return hStream
}

BASS_Volume(Volume=""){ ;sets or gets master volume: 0 (silent) to 1 (max)
    If Volume is Float
        Return DllCall("BASS\BASS_SetVolume", Float,Volume)
    Else
        Return DllCall("BASS\BASS_GetVolume", Float)
  }
BASS_GetDevice(hStream){  ;returns device number, otherwise -1
    Return DllCall("BASS\BASS_ChannelGetDevice", UInt,hStream)
  }
  

BASS_Seconds2Bytes(hStream,SecPos){  ;converts a position from seconds to bytes, returns on Error negative value
    Return DllCall("BASS\BASS_ChannelSeconds2Bytes", UInt,hStream, Double,SecPos, UInt64)
  }
BASS_Bytes2Seconds(hStream,BytePos){ ;converts a position from bytes to seconds, returns on Error negative value
    Return DllCall("BASS\BASS_ChannelBytes2Seconds", UInt,hStream, UInt64,BytePos, Double)
  }
BASS_GetLen(hStream){        ;returns playback length in bytes, returns on Error -1
    Return DllCall("BASS\BASS_ChannelGetLength", UInt,hStream, UInt,BASS_POS_BYTE := 0, UInt64)
  }
BASS_GetPos(hStream){      ;returns playback position in bytes, returns on Error -1
    Return DllCall("BASS\BASS_ChannelGetPosition", UInt,hStream, UInt,BASS_POS_BYTE := 0, UInt64)
  }
BASS_SetPos(hStream,BytePos){   ;sets playback position in bytes, returns 1, otherwise 0
    Return DllCall("BASS\BASS_ChannelSetPosition", UInt,hStream, UInt64,Bytepos, UInt,BASS_POS_BYTE := 0)
  }

BASS_GetLevel(WidthOrhStream, Byref LeftLevel,Byref RightLevel){ ;returns level (peak amplitude 0-32768) of a stream, returns on Error -1 or 0 when stream is stalled
    If ((LevelDWord := DllCall("BASS\BASS_ChannelGetLevel", UInt,hStream)) = -1)
        ErrorLevel := BASS_ErrorGetCode()
    If (LevelDWord > 0) {                       ;the level of the ...
        LeftLevel := LevelDWord & 0xffff            ;left channel is Returned in the low word (low 16-bits)
        RightLevel := (LevelDWord>>16) & 0xffff     ;Right channel is Returned in the high word (high 16-bits)
    }Else{
        LeftLevel = 0
        RightLevel = 0
      }
    ;Return LevelDWord
    Return LeftLevel
  }

BASS_IsSliding(hStream,Attrib){ ;returns 1 if attribute is sliding, otherwise 0, Attributes: 1=Freq, 2=Vol, 3=Pan, 4=EAXMix
    ;   BASS_ATTRIB_FREQ                := 1 ; 100 (min) to 100000 (max), 0 = original rate
    ;   BASS_ATTRIB_VOL                 := 2 ; 0 (silent) to 1 (full).
    ;   BASS_ATTRIB_PAN                 := 3 ; -1 (full left) to +1 (full right), 0 = centre
    ;   BASS_ATTRIB_EAXMIX              := 4 ; 0 (full dry) to 1 (full wet), -1 = automatically calculate the mix based on the distance (the default).
    If Attrib is not Number
      {
        If InStr(Attrib,"Freq")
            Attrib = 1
        Else If InStr(Attrib,"Vol")
            Attrib = 2
        Else If InStr(Attrib,"Pan")
            Attrib = 3
        Else If InStr(Attrib,"EAX")
            Attrib = 4
      }
    If Attrib not Between 1 and 4
        Return 0
    Return DllCall("BASS\BASS_ChannelIsSliding", UInt,hStream, UInt,Attrib)
  }
BASS_SetSliding(hStream,Attrib,NewValue,TimeMS){ ;set attribute from its current value to slide to new value in time period
    ;   BASS_ATTRIB_FREQ                := 1 ; 100 (min) to 100000 (max), 0 = original rate
    ;   BASS_ATTRIB_VOL                 := 2 ; 0 (silent) to 1 (full).
    ;   BASS_ATTRIB_PAN                 := 3 ; -1 (full left) to +1 (full right), 0 = centre
    ;   BASS_ATTRIB_EAXMIX              := 4 ; 0 (full dry) to 1 (full wet), -1 = automatically calculate the mix based on the distance (the default).
    If Attrib is not Number
      {
        If InStr(Attrib,"Freq")
            Attrib = 1
        Else If InStr(Attrib,"Vol")
            Attrib = 2
        Else If InStr(Attrib,"Pan")
            Attrib = 3
        Else If InStr(Attrib,"EAX")
            Attrib = 4
      }
    If Attrib not Between 1 and 4
        Return 0
    If NewValue is not Float
        Return 0
    If TimeMS is not Number
        Return 0
    Return DllCall("BASS\BASS_ChannelSlideAttribute", UInt,hStream, UInt,Attrib, Float,NewValue, UInt,TimeMS)
  }

BASS_GetCPU(){      ;returns CPU usage of BASS
    Return DllCall("BASS\BASS_GetCPU", Float)
  }
BASS_GetVersion(){  ;returns version of BASS that is loaded
    Return DllCall("BASS\BASS_GetVersion")
  }

; BASS_ProgressMeter
; based on idea by zed gecko  (StreamGUI, which comes with bass lib)
; adds a progress meter to a gui
BASS_ProgressMeter_Add(x = "", y = "", Width=300, Height=100, Color="green", Bgcolor="gray", ControlID="", GuiID=1){
    Return BASS_ProgressMeter(GuiID, ControlID, Width, Height//2, Color, BgColor, X, Y)
  }
; updates a progress meter for a stream
BASS_ProgressMeter_Update(hStream, ControlID="", GuiID=1){
    Return BASS_ProgressMeter(GuiID, ControlID, hStream, "???????????")
  }
BASS_ProgressMeter(GuiID, ControlID, WidthOrhStream, Height, Color="", Bgcolor="", X="", Y=""){
    global
    local  SegmentSpace,SegmentSize,TransferVar,PrevSegment,NOS,LeftLevel,RightLevel
    If (Height = "???????????"){
        SetControlDelay, -1
        Loop, % NOS := NumberOfProgressMeterSegments%ControlID% {
            PrevSegment := A_Index - 1
            GuiControlGet, TransferVar, %GuiID%:, ProgressMeterL%ControlID%%A_Index%
            GuiControl,%GuiID%:, ProgressMeterL%ControlID%%PrevSegment%, %TransferVar%
            GuiControlGet, TransferVar, %GuiID%:, ProgressMeterR%ControlID%%A_Index%
            GuiControl,%GuiID%:, ProgressMeterR%ControlID%%PrevSegment%, %TransferVar%
          }
        BASS_GetLevel(WidthOrhStream, LeftLevel, RightLevel)
        GuiControl,%GuiID%:, ProgressMeterL%ControlID%%NOS%, %LeftLevel%
        GuiControl,%GuiID%:, ProgressMeterR%ControlID%%NOS%, % 32768 - RightLevel
    }Else{
        SegmentSpace = 2                    ;Visible size of one segment in Pixel
        SegmentSize := SegmentSpace + 1
        NumberOfProgressMeterSegments%ControlID% := (WidthOrhStream // SegmentSize) - 1
        Gui, %GuiID%:Add, Progress, Range0-32768 vProgressMeterL%ControlID%0 w%SegmentSize% h%Height% %X% %Y% c%Color% BackgRound%BgColor% Vertical,
        Gui, %GuiID%:Add, Progress, Range0-32768 vProgressMeterR%ControlID%0 w%SegmentSize% h%Height% y+0 c%BgColor% BackgRound%Color% Vertical, 32769
        Loop, % NumberOfProgressMeterSegments%ControlID%{
            Gui, %GuiID%:Add, Progress, Range0-32768 vProgressMeterL%ControlID%%A_Index% w%SegmentSize% h%Height% xp+%SegmentSpace% yp-%Height% c%Color% BackgRound%BgColor% Vertical,
            Gui, %GuiID%:Add, Progress, Range0-32768 vProgressMeterR%ControlID%%A_Index% w%SegmentSize% h%Height% y+0 c%BgColor% BackgRound%Color% Vertical, 32769
          }
      }
    Return 1
  }

BASS_PluginLoad(File){   ;loads a plugin of BASS
    ;With any combination of these flags
    ;   BASS_UNICODE = 0x80000000 ;file is unicode
    Flags = 0
    If !hPlugin := DllCall("BASS\BASS_PluginLoad", UInt,&File, UInt,Flags)
        ErrorLevel := BASS_ErrorGetCode()
    Return hPlugin
  }
BASS_PluginFree(hPlugin=0){  ;frees a plugin of BASS (0 = All Plugins)
    If !(Ret := DllCall("BASS\BASS_PluginFree", UInt,hPlugin))
        ErrorLevel := BASS_ErrorGetCode()
    Return Ret
  }

BASS_ErrorGetCode(){ ;Return the error message as code and description
    static ErrorCodes :=
      (LTrim
        ";error codes returned by BASS_ErrorGetCode
        0  BASS_OK             all is OK
        1  BASS_ERROR_MEM      memory error
        2  BASS_ERROR_FILEOPEN can't open the file
        3  BASS_ERROR_DRIVER   can't find a free sound driver
        4  BASS_ERROR_BUFLOST  the sample buffer was lost
        5  BASS_ERROR_HANDLE   invalid handle
        6  BASS_ERROR_FORMAT   unsupported sample format
        7  BASS_ERROR_POSITION invalid position
        8  BASS_ERROR_INIT     BASS_Init has not been successfully called
        9  BASS_ERROR_START    BASS_Start has not been successfully called
        14 BASS_ERROR_ALREADY  already initialized/paused/whatever
        18 BASS_ERROR_NOCHAN   can't get a free channel
        19 BASS_ERROR_ILLTYPE  an illegal type was specified
        20 BASS_ERROR_ILLPARAM an illegal parameter was specified
        21 BASS_ERROR_NO3D     no 3D support
        22 BASS_ERROR_NOEAX    no EAX support
        23 BASS_ERROR_DEVICE   illegal device number
        24 BASS_ERROR_NOPLAY   not playing
        25 BASS_ERROR_FREQ     illegal sample rate
        27 BASS_ERROR_NOTFILE  the stream is not a file stream
        29 BASS_ERROR_NOHW     no hardware voices available
        31 BASS_ERROR_EMPTY    the MOD music has no sequence data
        32 BASS_ERROR_NONET    no internet connection could be opened
        33 BASS_ERROR_CREATE   couldn't create the file
        34 BASS_ERROR_NOFX     effects are not enabled
        37 BASS_ERROR_NOTAVAIL requested data is not available
        38 BASS_ERROR_DECODE   the channel is a decoding channel
        39 BASS_ERROR_DX       a sufficient DirectX version is not installed
        40 BASS_ERROR_TIMEOUT  connection timedout
        41 BASS_ERROR_FILEFORM unsupported file format
        42 BASS_ERROR_SPEAKER  unavailable speaker
        43 BASS_ERROR_VERSION  invalid BASS version (used by add-ons)
        44 BASS_ERROR_CODEC    codec is not available/supported
        45 BASS_ERROR_ENDED    the channel/file has ended
        -1 BASS_ERROR_UNKNOWN  some other mystery problem"
      )
    Error := DllCall("BASS\BASS_ErrorGetCode", Int)
    Needle := "m`n)^" Error " +\w*\s*(?P<Value>.*)$"
    RegExMatch(ErrorCodes, Needle, Return)
    Return Error " = " ReturnValue
  }

SpecialGuest
Posts: 26
Joined: 15 May 2016, 07:49

Re: Recording from mic - what are the new methods?

06 Jan 2018, 11:24

Thanks for the assisstance. No more crashes finally!
Yes, I think that will do nicely. The channeldata is not a big issue.

If you wouldn't mind I'd love to know how this works logically:
t :=110-NumGet(buf,4*(A_Index-1),"Float")*3000
As I don't quite grasp it. Like why 110 and 3000 ?
I noticed those changed so I figured I'd ask.
Last edited by SpecialGuest on 12 Nov 2018, 14:58, edited 1 time in total.
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: Recording from mic - what are the new methods?

06 Jan 2018, 11:45

Like why 110 and 3000 ?
It is just to scale it and get it fitted into the window dimensions.The window height is 120 ,if the output of "NumGet(buf,4*(A_Index-1),"Float")*3000" is 0 then the yposition is 110-0=110 or the baseline is 10 above bottom (120-110) .If the output is higher the value gets smaller so ypos goes up in the window.

The 3000 is just try and error to get a value that is around 100 when i kick my mic ...............

Greetings and i have to thank you i just learned a few things in win10 and gave me ideas :D
SpecialGuest
Posts: 26
Joined: 15 May 2016, 07:49

Re: Recording from mic - what are the new methods?

06 Jan 2018, 11:54

Really glad to hear that gave you some ideas. And thanks for the info again ;) Makes sense now.
Feel free to share your experiments with us, I think I can speak for everyone saying we're always looking forward to see them.
Greetz 8-)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: masheen, mikeyww and 177 guests