Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Wrapper for BASS.dll (2.4.5.0)


  • Please log in to reply
18 replies to this topic
toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
This is a mod of the BASS wrapper done by k3ph. This wrapper only uses global variables when needed. And it simplifies some actions (I hope).

You'll need the bass.dll => <!-- w -->www.un4seen.com<!-- w -->

The wrapper for bass.dll => <!-- w -->www.autohotkey.net/~toralf/BASS/bass.ahk<!-- w -->

And the bass_acc.dll and wrapper for AAC files: <!-- w -->www.un4seen.com<!-- w --> &
<!-- w -->www.autohotkey.net/~toralf/BASS/bassaac.ahk<!-- w -->

With time I might add more wrappers for add-ons. Currently AAC is all I needed.

A Demo script will be posted soon.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

acc failure
  • Guests
  • Last active:
  • Joined: --
toralf, a little help please. I have put the two ahk files and both bass.dll and bass_aac.dll into a common directory. I have futher attemped to fill in the dll path and dll name into bassaac.ahk, but obviously not correctly. A simple demo script (as promised :wink: ) to load and play an acc file would be greatly appreciated.

Trubbleguy
  • Members
  • 122 posts
  • Last active: Jan 15 2017 10:50 AM
  • Joined: 20 Jan 2007
Any chance of that example code to set us on the right path?
By any chance have you dabbled in the Bass_fx.dll and figured out tempo and keychange? i have been poking around in karaoke for a few years and this bass wrapping might be the answer im looking for.

Thanks in advance, I can happily say that Toralfcode has wormed its way permanently into at least half of my own projects, :lol:

jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005
skwire was kind enough to point me to this thread. I completely missed it when it was first published (March 2010).

The BASS library published by k3ph (link: here) is significantly more robust that this library but it is very complex and I imagine that a lot people never bothered to play with it because it is overwhelming. The library also uses a very large number of global variables.

The toralf version of the BASS library (this thread) is a significantly scaled down version of k3ph's BASS library but it appears to do most of the stuff that a developer needs to create a basic media player.

There are no examples for this library so I created a couple while learning how to use this library. I'm sharing just in case anyone else can benefit from them.

Requirements: These examples need the bass.ahk and the bass.dll files. See the first post in this thread for links to these files.

Standard Example:
#NoEnv
#SingleInstance Force

OnExit Exit

;-- Initialize
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
BASS_Load()
hStream:=""


;-- Build GUI
gui Margin,0,0
gui Add,Button,w70 h40,Open
gui Add,Button,x+0 wp hp,Play
gui Add,Button,x+0 wp hp,Pause
gui Add,Button,x+0 wp hp,Stop
gui,Add,Button,x+0 wp hp,Rev10
gui,Add,Button,x+0 wp hp,Middle
gui,Add,Button,x+0 wp hp,Fwd10
gui Show

gosub ButtonOpen
return


GUIEscape:
GUIClose:
if hStream
    hStream:=BASS_Stop()

ExitApp


ButtonOpen:
if hStream
    hStream:=BASS_Stop()

if not DefaultFolder
    DefaultFolder:=A_MyDocuments

gui +OwnDialogs
FileSelectFile MediaFile,1,%DefaultFolder%,Choose a media file
if (MediaFile="")
   return

SplitPath MediaFile,,DefaultFolder

gosub ButtonPlay
return


ButtonPlay:
if not hStream
    hStream:=BASS_Play(MediaFile)
 else
    {
    Status:=BASS_IsPlaying(hStream)
    if (Status=BASS_ACTIVE_PLAYING)
        BASS_SetPos(hStream,0)
     else
        if (Status=BASS_ACTIVE_PAUSED)
            BASS_Pause()
         else  ;-- Everything else
            {
            hStream:=BASS_Stop()  ;-- Necessary if stalled
            hStream:=BASS_Play(MediaFile)
            }
    }

return


ButtonPause:
if hStream
    {
    Status:=BASS_IsPlaying(hStream)
    if Status in %BASS_ACTIVE_PLAYING%,%BASS_ACTIVE_STALLED%,%BASS_ACTIVE_PAUSED%
        BASS_Pause()
    }


return


ButtonStop:
if hStream
    hStream:=BASS_Stop()

return


ButtonFwd10:
if hStream
    {
    Status:=BASS_IsPlaying(hStream)
    if Status in %BASS_ACTIVE_PLAYING%,%BASS_ACTIVE_PAUSED%
        {
        NewPos:=BASS_Bytes2Seconds(hStream,BASS_GetPos(hStream))+10
        MaxPos:=BASS_Bytes2Seconds(hStream,BASS_GetLen(hStream))
        if (NewPos>=MaxPos)
            NewPos:=MaxPos-0.05

        BASS_SetPos(hStream,BASS_Seconds2Bytes(hStream,NewPos))
        }
    }

return


ButtonMiddle:
if hStream
    {
    Status:=BASS_IsPlaying(hStream)
    if Status in %BASS_ACTIVE_PLAYING%,%BASS_ACTIVE_PAUSED%
        {
        NewPos:=BASS_Bytes2Seconds(hStream,BASS_GetLen(hStream))/2
        BASS_SetPos(hStream,BASS_Seconds2Bytes(hStream,NewPos))
        }
    }

return


ButtonRev10:
if hStream
    {
    Status:=BASS_IsPlaying(hStream)
    if Status in %BASS_ACTIVE_PLAYING%,%BASS_ACTIVE_PAUSED%
        {
        NewPos:=BASS_Bytes2Seconds(hStream,BASS_GetPos(hStream))-10
        if (NewPos<0)
            NewPos:=0

        BASS_SetPos(hStream,BASS_Seconds2Bytes(hStream,NewPos))
        }
    }

return


Exit:
BASS_Free()
ExitApp


#include bass.ahk

Playlist Example:
#NoEnv
#SingleInstance Force

OnExit Exit

;-- Initialize
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
BASS_Load()
hStream:=""

;-- Build GUI
gui Margin,0,0
gui Add,Button,w100 h50        gOpen ,Open
gui Add,Button,x+0 wp hp       gPlay ,Play
gui Add,Button,x+0 wp hp       gPause,Pause
gui Add,Button,x+0 wp hp vStop gStop ,Stop
gui Add,Button,x+0 wp hp       gPrev ,Prev
gui Add,Button,x+0 wp hp       gNext ,Next

gui Add
   ,Progress
   ,x+0 w10 hp
        || cNavy
        || Range0-32768
        || Vertical
        || vLevelLeft
        
gui Add
   ,Progress
   ,x+0 w10 hp
        || cNavy
        || Range0-32768
        || Vertical
        || vLevelRight


gui Add,Text,xm w40,%A_Space%Pos:
gui Add
   ,Slider
   ,x+0 w270
        || +Disabled  ;-- Start off disabled
        || ToolTip
        || vPosSlider
        || gPosSlider

gui Add,Text,x+0 w40 hp,%A_Space%Vol:
gui Add
   ,Slider
   ,x+0 w270 hp
        || ToolTip
        || vVolSlider
        || gVolSlider
   ,% BASS_Volume()*100


gui Add
   ,ListView
   ,xm w620 r20
        || Count1000
        || -Hdr
        || vPlaylist
        || gPlaylistAction
   ,Media File Name

gui Show

;-- Start 'R Up
gosub Open
return


GUIEscape:
GUIClose:
gosub Stop
ExitApp


PlaylistAction:
if (A_GuiEvent="DoubleClick")
    {
    ;-- Anything selected? (Seems redundant for a double-click, but it's not)
    if LV_GetCount("Selected")
        {
        PlaylistIndex:=A_EventInfo-1
        gosub Next
        }
    }

return


Open:

;-- Attach messages/dialogs to current GUI
gui +OwnDialogs

;-- Close if anything is open
if hStream
    gosub Stop

;-- Initialize
LV_Delete()
if MediaPath is Space
    MediaPath:=A_MyDocuments

;-- Browse for it
gui +OwnDialogs
FileSelectFolder
    ,MediaFolder
    ,*%MediaPath%
    ,0
    ,Add media folder...

;-- Nothing selected?
If ErrorLevel
    {
    MsgBox 48,Open Failure,No media folder selected.
    return
    }

MediaPath:=MediaFolder

;[=====================]
;[  Populate playlist  ]
;[=====================]
;-- Redraw off
GUIControl -Redraw,Playlist

;-- Find media files
$BatchLines:=A_BatchLines
SetBatchLines 50ms
Loop %MediaFolder%\*.*,,1
    if A_LoopFileExt in mp3,wav  ;-- Add more extensions if desired
        LV_Add("",A_LoopFileLongPath)

SetBatchLines %$BatchLines%

;-- Redraw on
GUIControl +Redraw,Playlist

;-- Anything loaded
if LV_GetCount()=0
    {
    MsgBox 48,Open Failure,No media files found.
    return
    }

;-- Get it started
PlaylistIndex:=0
gosub Next
return


Play:
if not hStream
    hStream:=BASS_Play(MediaFile)
 else
    {
    Status:=BASS_IsPlaying(hStream)
    if (Status=BASS_ACTIVE_PLAYING)
        BASS_SetPos(hStream,0)
     else
        if (Status=BASS_ACTIVE_PAUSED)
            BASS_Pause()
         else  ;-- Everything else
            {
            hStream:=BASS_Stop()  ;-- Necessary if stalled
            hStream:=BASS_Play(MediaFile)
            }
    }

;-- Start/Restart timers
SetTimer NotifyEOP,250
GUIControl Enable,PosSlider
SetTimer UpdatePosSlider,250
SetTimer UpdateLevel,50
return


Pause:
if hStream
    {
    Status:=BASS_IsPlaying(hStream)
    if Status in %BASS_ACTIVE_PLAYING%,%BASS_ACTIVE_STALLED%,%BASS_ACTIVE_PAUSED%
        BASS_Pause()
    }

return


Stop:
if hStream
    hStream:=BASS_Stop()

;-- NotifyEOF
SetTimer NotifyEOP,Off

;-- Position
SetTimer UpdatePosSlider,Off
GUIControl,,PosSlider,0
GUIControl Disable,PosSlider

;-- Level
SetTimer UpdateLevel,Off
GUIControl,,LevelLeft,0
GUIControl,,LevelRight,0
return


Prev:
if (PlaylistIndex>1)
    {
    PlaylistIndex-=2
    gosub Next
    }

return


Next:
Sleep 0  ;-- (Helps to) keep this thread from stepping on itself
if hStream
    gosub Stop

;-- At the end?
if (PlaylistIndex>=LV_GetCount())
    return

;-- Increment index
PlayListIndex++

;-- UnSelect all, select new item
LV_Modify(0,"-Select")
LV_Modify(PlaylistIndex,"+Select +Focus +Vis")

;-- Collect media file name
LV_GetText(MediaFile,PlaylistIndex,1) 

;-- Play it
gosub Play
    ;-- This command will open the file and establish a stream

;-- Collect length (in seconds)
MediaLength:=BASS_Bytes2Seconds(hStream,BASS_GetLen(hStream))
    ;-- The length of the media file is collected once on open/play.  The value
    ;   is used by the PosSlider routine.

return


PosSlider:
if hStream
    {
    Status:=BASS_IsPlaying(hStream)
    if Status in %BASS_ACTIVE_PLAYING%,%BASS_ACTIVE_PAUSED%
        {
        if (PosSlider=100)  ;-- Moved to the very end (BASS doesn't respond to this)
            Pos:=BASS_GetLen(hStream)-1024  ;-- This usually works.  Need to determine if it the best solution.
         else
            Pos:=BASS_Seconds2Bytes(hStream,MediaLength*(PosSlider/100))

        BASS_SetPos(hStream,Pos)
        }

    ;-- Reset focus (anything but the PosSlider)
    GUIControl Focus,Stop
    }

return


UpdatePosSlider:
if hStream
    {
    Status:=BASS_IsPlaying(hStream)
    if Status in %BASS_ACTIVE_PLAYING%,%BASS_ACTIVE_PAUSED%
        {
        ;-- Only update PosSlider if object is NOT in focus
        GUIControlGet Control,FocusV
        if (Control<>"PosSlider")
            GUIControl,,PosSlider,% (BASS_Bytes2Seconds(hStream,BASS_GetPos(hStream))/MediaLength)*100
        }
    }

return


UpdateLevel:
if hStream
    {
    if (BASS_IsPlaying(hStream)=BASS_ACTIVE_PLAYING)
        {
        BASS_GetLevel(hStream,LevelLeft,LevelRight)
        GUIControl,,LevelLeft,%LevelLeft%
        GUIControl,,LevelRight,%LevelRight%
        }
     else
        {
        GUIControl,,LevelLeft,0
        GUIControl,,LevelRight,0
        }
    }

return


VolSlider:
Bass_Volume(VolSlider/100)

;-- Reset focus (anything but the VolSlider)
GUIControl Focus,Stop
return


NotifyEOP:
if hStream
    if (BASS_IsPlaying(hStream)=BASS_ACTIVE_STOPPED)
        gosub Next

return


Exit:
BASS_Free()
ExitApp


#include bass.ahk

Although these examples are AutoHotkey_L ready (I only tested using the Unicode version), they won't work on the most recent versions of AuthoHotkey_L because this BASS library is not AutoHotkey_L and/or Unicode ready. If anyone is interested in a tweaked-for-unicode version, PM me and I'll send you what I have. There are only minor changes to the current library but I haven't done any significant testing on it so it's not forum ready.

Edit: Updated the Playlist example to include progress bars for the left and right channels.

emmanuel d
  • Members
  • 519 posts
  • Last active: Jul 15 2017 12:04 PM
  • Joined: 29 Jan 2009
how about that unicode?
i have this:
#SingleInstance Force ; [force|ignore|off]
#Persistent ; Keeps a script permanently running
file:=A_ScriptDir "\What I Am.mp3"
msgbox,% BASS_DLLCALL		:= DllCall("LoadLibrary","str",A_ScriptDir "\bass.dll")
msgbox,% DllCall(A_ScriptDir . "\bass.dll\BASS_Init",Int,-1,Int,44100,Int,0,UInt,0,UInt,0)
; VarSetCapacity(ANSItext, StrPut(file, ""))
; StrPut(text, &ANSItext, "")
msgbox,% hMedia:= DllCall(A_ScriptDir . "\bass.dll\BASS_StreamCreateFile", UInt, false, UInt, &file, UInt64,0, UInt64,0, UInt,0)
msgbox,% DllCall(A_ScriptDir . "\bass.dll\BASS_ChannelPlay", UInt,hMedia, Int,1, Int)
but never get it to work with ahk_L unicode.
hMedia is never good.
if anybody has that figuered ou i would be graetfull. :D

Stopwatch emdkplayer
the code i post falls under the: WTFYW-WTFPL license

http://www.ahkscript.org/ the new forum


nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
At least &file, if not other parameters, should be UPtr, but if the function expects an ANSI string, you should probably use AStr, file.

jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005

how about that unicode?
i have this:

[snip]

but never get it to work with ahk_L unicode.
hMedia is never good.
if anybody has that figuered ou i would be graetfull. :D

Although I didn't try to run your code, you appear to be close.

For the most part, the BASS API supports Unicode, but not by default. You have to tell it that you want to communicate in Unicode (UTF-16). This is accomplished by including the BASS_UNICODE flag when needed.

The following is an example of the BASS_Open function from the library that has been converted to support Unicode. Of course, it won't run without the supporting library, but it will give you an idea of the changes that need to be made:

BASS_Open(p_MediaFile,p_Flags=0)
    {
    Static BASS_STREAM_AUTOFREE:=0x40000
          ,BASS_UNICODE        :=0x80000000

    ;-- Media file exist?
    IfNotExist %p_MediaFile%
        {
        outputdebug
            ,Function: %A_ThisFunc% - The media file can't be found: %p_File%

        Return False
        }

    ;-- Parameters
    if A_IsUnicode
        p_Flags|=BASS_UNICODE

    ;-- Create stream
    hStream:=DllCall("bass\BASS_StreamCreateFile"
                    ,"UInt",False                       ;-- mem (TRUE=Stream from memory)
                    ,"UInt",&p_MediaFile                ;-- file
                    ,"UInt64",0                         ;-- offset (0=Beginning)
                    ,"UInt64",0                         ;-- length (0=Use all)
                    ,"UInt",p_Flags)                    ;-- flags

    if (hStream=0)
        {
        ErrorLevel:=BASS_ErrorGetCode()
        outputdebug,
           (ltrim join`s
            Function: %A_ThisFunc% - Unable to create a stream from file:
            %p_File%
            `n-------- Error: %ErrorLevel%
           )
        
        Return False
        }

    ;-- Return the new stream's handle
    Return hStream
    }
To convert the entire library to support Unicode, just look for the API functions that use a "flag" field of some sort. Then check the documentation to see if the BASS_UNICODE flag is supported. If it is, just use the A_IsUnicode system variable to determine whether it should be included or not.

The BASS documentation can be found here:
http://www.un4seen.com/doc/

I hope this helps.

emmanuel d
  • Members
  • 519 posts
  • Last active: Jul 15 2017 12:04 PM
  • Joined: 29 Jan 2009

I hope this helps.

It does.
what i was missing was
BASS_UNICODE        :=0x80000000
so this wil work on both ansi and unicode:
#SingleInstance Force ; [force|ignore|off]
#Persistent ; Keeps a script permanently running
BASS_UNICODE:=0x80000000
file := A_ScriptDir "\What I Am.mp3"
msgbox,% BASS_DLLCALL		:= DllCall("LoadLibrary","str",A_ScriptDir "\bass.dll")
msgbox,% DllCall(A_ScriptDir . "\bass.dll\BASS_Init",Int,-1,Int,44100,Int,0,UInt,0,UInt,0)
msgbox,% hMedia:= DllCall(A_ScriptDir . "\bass.dll\BASS_StreamCreateFile", UInt, false, UInt, &file, UInt64,0, UInt64,0, UInt,A_IsUnicode ? BASS_UNICODE : 0)
msgbox,% DllCall(A_ScriptDir . "\bass.dll\BASS_ChannelPlay", UInt,hMedia, Int,1, Int)
return
thanks alot to point this out

you can see that i do not use the library's that way i can do this in 5 lines instead of 500 :D

Stopwatch emdkplayer
the code i post falls under the: WTFYW-WTFPL license

http://www.ahkscript.org/ the new forum


emmanuel d
  • Members
  • 519 posts
  • Last active: Jul 15 2017 12:04 PM
  • Joined: 29 Jan 2009

At least &file, if not other parameters, should be UPtr, but if the function expects an ANSI string, you should probably use AStr, file.

i tested:
hMedia:= DllCall(A_ScriptDir . "\bass.dll\BASS_StreamCreateFile", UInt, false, str,A_ScriptDir "\What I Am.mp3", UInt64,0, UInt64,0, UInt,A_IsUnicode ? BASS_UNICODE : 0)
; hMedia:= DllCall(A_ScriptDir . "\bass.dll\BASS_StreamCreateFile", UInt, false, str,file, UInt64,0, UInt64,0, UInt,A_IsUnicode ? BASS_UNICODE : 0)
;hMedia:= DllCall(A_ScriptDir . "\bass.dll\BASS_StreamCreateFile","UInt",false,A_IsUnicode ? "WStr" : "AStr",file, UInt64,0, UInt64,0, UInt,A_IsUnicode ? BASS_UNICODE : 0)
; hMedia:= DllCall(A_ScriptDir . "\bass.dll\BASS_StreamCreateFile", UInt, false, A_PtrSize ? "UPtr" : "UInt",&file, UInt64,0, UInt64,0, UInt,A_IsUnicode ? BASS_UNICODE : 0)
They all work in ahk_L
thx Nimda for pointing to it.

Stopwatch emdkplayer
the code i post falls under the: WTFYW-WTFPL license

http://www.ahkscript.org/ the new forum


ahkiot0
  • Members
  • 51 posts
  • Last active: Mar 11 2015 12:45 AM
  • Joined: 31 May 2008
anybody can add to script checkbox & slide?

1. Loop
2. Reverb
3. Random (Shuffle)
4. Panarama Channel (Left\Right)

bleasby
  • Guests
  • Last active:
  • Joined: --
Anyone have the bass.ahk file???

I cannot find it anyware!!!

  • Guests
  • Last active:
  • Joined: --
Bass.ahk

Diamond
  • Members
  • 198 posts
  • Last active: Dec 02 2015 11:18 AM
  • Joined: 31 Mar 2006
Anyone have the bass.ahk and bassaac.ahk from this thread? The links seem to be broken.

MarcroSoft
  • Members
  • 4 posts
  • Last active: Oct 21 2015 01:27 AM
  • Joined: 15 Oct 2015

Hi.

All the links I can find to these files are dead.

If anyone have them, please post them if you can.

I am moving from autoit to autohotkey and I love it so far, thank you!



noname
  • Members
  • 650 posts
  • Last active:
  • Joined: 12 Nov 2011

These are original versions of what i have from k3ph.

 

https://dl.dropboxus...08/k3phbass.zip

 

 

I made some small change for using bass.ahk with ahk unicode .

; 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])


;set Include directory for plugins
#Include %A_ScriptDir%\

;include effects & handlers
#Include *i basstags.ahk
#Include *i bassfx.ahk
#Include *i bassvfx.ahk
#Include *i bassenc.ahk
#Include *i bassmix.ahk
#Include *i bassvis.ahk
#Include *i bassvst.ahk
#Include *i basswadsp.ahk
#Include *i bassvideo.ahk

;include format plugins
#Include *i basscd.ahk
#Include *i bassmidi.ahk
#Include *i bassflac.ahk
#Include *i basswma.ahk
#Include *i basswv.ahk
#Include *i bassaac.ahk
#Include *i bassape.ahk
#Include *i bassmpc.ahk
#Include *i bassac3.ahk
#Include *i bassalac.ahk
#Include *i bassspx.ahk
#Include *i basstta.ahk
#Include *i bassofr.ahk

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
}


winXP  and ahk unicode