Author Topic: BASS_MusicLoad() and BASS_StreamCreateFile() crashes with Delphi? [SOLVED]  (Read 4936 times)

3delite

  • Posts: 925
Hi!

I am developing a .dll to be used together with BASS. I am trying to auto-detect the BASS version that is already in the process space.
I need a legacy support for BASS 2.3 and support for the new BASS 2.4 too.
I do the following:
1. Get or load the BASS.dll with LoadLibrary() (if not already loaded) or GetModuleHandle() (if already loaded):

Code: [Select]
procedure CheckBASSAvailability(LoadBASS: Boolean);
var
    Address: Pointer;
begin

    BASS_LibHandle := GetModuleHandle(PChar(FILENAME_DLL_BASS));

    if (BASS_LibHandle = 0)
    AND LoadBASS
        then BASS_LibHandle := SafeLoadLibrary(PChar(FILENAME_DLL_BASS));

    if BASS_LibHandle <> 0 then begin
        BASS_GetVersion := GetProcAddress(BASS_LibHandle, PChar('BASS_GetVersion'));

        t_BASS23_Init := GetProcAddress(BASS_LibHandle, PChar('BASS_Init'));
        t_BASS23_SetConfig := GetProcAddress(BASS_LibHandle, PChar('BASS_SetConfig'));
        t_BASS23_MusicLoad := GetProcAddress(BASS_LibHandle, PChar('BASS_MusicLoad'));
        t_BASS23_StreamCreateFile := GetProcAddress(BASS_LibHandle, PChar('BASS_StreamCreateFile'));

        //* This is ok the proc address seems valid <> 0
        //Address := Pointer(@t_BASS23_StreamCreateFile);
        //Showmessage(IntToHex(Integer(Address), 8));

        t_BASS23_ChannelGetLength := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetLength'));
        t_BASS23_ChannelGetInfo := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetInfo'));
        t_BASS23_ChannelIsActive := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelIsActive'));
        t_BASS23_ChannelGetData := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetData'));
        t_BASS23_ChannelGetPosition := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetPosition'));
        t_BASS23_ChannelSetPosition := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelSetPosition'));
        t_BASS23_ChannelBytes2Seconds := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelBytes2Seconds'));
        t_BASS23_ChannelSetSync := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelSetSync'));
        t_BASS23_MusicFree := GetProcAddress(BASS_LibHandle, PChar('BASS_MusicFree'));
        t_BASS23_StreamFree := GetProcAddress(BASS_LibHandle, PChar('BASS_StreamFree'));
        t_BASS23_GetDevice := GetProcAddress(BASS_LibHandle, PChar('BASS_GetDevice'));
        t_BASS23_ChannelPlay := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelPlay'));
        t_BASS23_ChannelStop := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelStop'));
        t_BASS23_ChannelPause := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelPause'));
        t_BASS23_ErrorGetCode := GetProcAddress(BASS_LibHandle, PChar('BASS_ErrorGetCode'));

        t_BASS24_Init := GetProcAddress(BASS_LibHandle, PChar('BASS_Init'));
        t_BASS24_SetConfig := GetProcAddress(BASS_LibHandle, PChar('BASS_SetConfig'));
        t_BASS24_MusicLoad := GetProcAddress(BASS_LibHandle, PChar('BASS_MusicLoad'));
        t_BASS24_StreamCreateFile := GetProcAddress(BASS_LibHandle, PChar('BASS_StreamCreateFile'));
        t_BASS24_ChannelGetLength := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetLength'));
        t_BASS24_ChannelGetInfo := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetInfo'));
        t_BASS24_ChannelIsActive := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelIsActive'));
        t_BASS24_ChannelGetData := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetData'));
        t_BASS24_ChannelGetPosition := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelGetPosition'));
        t_BASS24_ChannelSetPosition := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelSetPosition'));
        t_BASS24_ChannelBytes2Seconds := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelBytes2Seconds'));
        t_BASS24_ChannelSetSync := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelSetSync'));
        t_BASS24_MusicFree := GetProcAddress(BASS_LibHandle, PChar('BASS_MusicFree'));
        t_BASS24_StreamFree := GetProcAddress(BASS_LibHandle, PChar('BASS_StreamFree'));
        t_BASS24_GetDevice := GetProcAddress(BASS_LibHandle, PChar('BASS_GetDevice'));
        t_BASS24_ChannelPlay := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelPlay'));
        t_BASS24_ChannelStop := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelStop'));
        t_BASS24_ChannelPause := GetProcAddress(BASS_LibHandle, PChar('BASS_ChannelPause'));
        t_BASS24_ErrorGetCode := GetProcAddress(BASS_LibHandle, PChar('BASS_ErrorGetCode'));
    end;

    if (BASS_LibHandle <> 0)
        then BASS_Available := True
        else BASS_Available := False;

    BASS_Version := HIWORD(BASS_GetVersion);

    if BASS_Available then begin
        case BASS_Version of
            BASSVERSION23: BASS_ActiveDevice := t_BASS23_GetDevice;
            BASSVERSION24: BASS_ActiveDevice := t_BASS24_GetDevice;
            else begin
                BASS_ActiveDevice := t_BASS24_GetDevice;
            end;
        end;
    end;

end;

the handles seems valid, they are not 0!
After it is loaded I call BASS_GetVersion() it also gives a valid value (2.3 or 2.4) it works!
BASS_GetDevice() also works returns 1.

Code: [Select]
function InitializeBASS(Device: Integer; freq: DWORD; win: HWND): LongBool;
var
  Error: Integer;
begin
    Result := False;
    case BASS_Version of
        BASSVERSION23: begin
            if t_BASS23_Init(Device, freq, 0, win, nil) then begin
                BASS_ActiveDevice := t_BASS23_GetDevice;
                Result := True;
                t_BASS23_SetConfig(BASS_CONFIG_BUFFER, 1000 * 2);
            end;
            Error := t_BASS23_ErrorGetCode;
            if Error = BASS_ERROR_ALREADY then begin
                Result := True;
            end;
        end;
        BASSVERSION24: begin
            if t_BASS24_Init(Device, freq, 0, win, nil) then begin
                BASS_ActiveDevice := t_BASS24_GetDevice;
                Result := True;
                t_BASS24_SetConfig(BASS_CONFIG_BUFFER, 1000 * 2);
            end;
            Error := t_BASS24_ErrorGetCode;
            if Error = BASS_ERROR_ALREADY then begin
                Result := True;
            end;
        end
        else begin
            if t_BASS24_Init(Device, freq, 0, win, nil) then begin
                BASS_ActiveDevice := t_BASS24_GetDevice;
                Result := True;
                t_BASS24_SetConfig(BASS_CONFIG_BUFFER, 1000 * 2);
            end;
            Error := t_BASS24_ErrorGetCode;
            if Error = BASS_ERROR_ALREADY then begin
                Result := True;
            end;
        end;
    end;

end;

BASS_ErrorGetCode() returns the expected BASS_ERROR_ALREADY error.

But when I call BASS_MusicLoad() or BASS_StreamCreateFile() the app crashes with booth BASS 2.3 or BASS 2.4 with access violation at address 0 read of address 0!

Code: [Select]
       if Channel = 0 then begin
            Channel := FD_BASS_MusicLoad(FALSE, PWideChar(FileName), 0, 0, BASS_MUSIC_DECODE OR BASS_SAMPLE_FLOAT OR BASS_MUSIC_STOPBACK OR BASS_MUSIC_CALCLEN OR BASS_UNICODE OR BASS_STREAM_AUTOFREE, 0);   // BASS_SAMPLE_MONO
            if Channel = 0
                then Channel := FD_BASS_StreamCreateFile(False, PWideChar(FileName), 0, 0, BASS_STREAM_DECODE OR BASS_SAMPLE_FLOAT OR BASS_MP3_SETPOS OR BASS_UNICODE OR BASS_STREAM_AUTOFREE);
        end;

The wrapper that it calls, looks like:

Code: [Select]
function FD_BASS_MusicLoad(mem: BOOL; f: Pointer; offset, length, flags, freq: DWORD): DWORD; stdcall;
begin
    case BASS_Version of
        BASSVERSION23: Result := t_BASS23_MusicLoad(mem, f, offset, length, flags, freq);
        BASSVERSION24: Result := t_BASS24_MusicLoad(mem, f, offset, length, flags, freq);
        else begin
            Result := t_BASS24_MusicLoad(mem, f, offset, length, flags, freq);
        end;
    end;
end;

function FD_BASS_StreamCreateFile(mem: BOOL; f: Pointer; offset, length: QWORD; flags: DWORD): DWORD; stdcall;
begin
    case BASS_Version of
        BASSVERSION23: Result := t_BASS23_StreamCreateFile(mem, f, offset, length, flags);
        BASSVERSION24: Result := t_BASS24_StreamCreateFile(mem, f, offset, length, flags);
        else begin
            Result := t_BASS24_StreamCreateFile(mem, f, offset, length, flags);
        end;
    end;
end;

The error is thrown right after leaving the above functions.

The calling conventions are all stdcall.

The error is thrown with MP3 and XM files (and also Flac, as the 2.3 Flac add-on is also in the process space - it should auto detect and load Flac files with BASS_StreamCreateFile(), right?).

I am using WinXP Pro SP3 and Delphi 2009.

What could it be? Is it something Delphi specific I am doing wrong?

Also attached the unit I am using...

Best regards
3delite
« Last Edit: 26 Sep '09 - 19:18 by 3delite »

3delite

  • Posts: 925
Added a BASS_ErrorGetcode() line after the failing calls and they return:
1. BASS_MusicLoad() with an MP3 returns BASS_ERROR_FILEOPEN
2. BASS_StreamCreateFile() returns  BASS_ERROR_NOTAVAIL

Any ideas?

Best regards
3delite

Ian @ un4seen

  • Administrator
  • Posts: 20774
But when I call BASS_MusicLoad() or BASS_StreamCreateFile() the app crashes with booth BASS 2.3 or BASS 2.4 with access violation at address 0 read of address 0!

That sounds like the function pointers (t_BASS23_MusicLoad/etc) may be 0. Have you confirmed that they aren't, eg. via sticking a break-point on the calls? Another possibility is that they aren't defined with the correct parameters or calling convention; please post the definitions to confirm whether that's the case.

3delite

  • Posts: 925
The function pointers are non-zero. I checked that (once again). 0 AVs suggest that thay are 0, but this isn't the case (this was that I first checked).
All the functions are loaded the same way. Why a call to BASS_GetDevice() works, and a call to BASS_StreamCreateFile() doesn't?
The calling convention is stdcall, this also is not the problem:

Code: [Select]
var
  BASS_Available: Boolean = False;
  BASS_ActiveDevice: Integer;
  BASS_LibHandle: THandle;
  BASS_Version: DWORD;
  BASS_GetVersion: function: DWORD; stdcall;

  t_BASS23_Init: function(device: Integer; freq, flags: DWORD; win: HWND; clsid: PGUID): BOOL; stdcall;
  t_BASS23_SetConfig: function(option, value: DWORD): DWORD; stdcall;
  t_BASS23_MusicLoad: function(mem: BOOL; f: Pointer; offset, length, flags, freq: DWORD): DWORD; stdcall;
  t_BASS23_StreamCreateFile: function(mem: BOOL; f: Pointer; offset, length: QWORD; flags: DWORD): DWORD; stdcall;
  t_BASS23_ChannelGetLength: function(handle: DWORD): Int64; stdcall;
  t_BASS23_ChannelGetInfo: function(handle: DWORD; var info: BASS23_CHANNELINFO):BOOL; stdcall;
  t_BASS23_ChannelIsActive: function(handle: DWORD): DWORD; stdcall;
  t_BASS23_ChannelGetData: function(handle: DWORD; buffer: Pointer; length: DWORD): DWORD; stdcall;
  t_BASS23_ChannelGetPosition: function(handle: DWORD): QWORD; stdcall;
  t_BASS23_ChannelSetPosition: function(handle: DWORD; pos: QWORD): BOOL; stdcall;
  t_BASS23_ChannelBytes2Seconds: function(handle: DWORD; pos: QWORD): FLOAT; stdcall;
  t_BASS23_ChannelSetSync: function(handle: DWORD; stype: DWORD; param: QWORD; proc: SYNCPROC; user: Pointer): HSYNC; stdcall;
  t_BASS23_MusicFree: function(Channel: Cardinal): Bool; stdcall;
  t_BASS23_StreamFree: function(Channel: Cardinal): Bool; stdcall;
  t_BASS23_GetDevice: function: DWORD; stdcall;
  t_BASS23_ChannelPlay: function(handle: DWORD; restart: BOOL): BOOL; stdcall;
  t_BASS23_ChannelStop: function(handle: DWORD): BOOL; stdcall;
  t_BASS23_ChannelPause: function(handle: DWORD): BOOL; stdcall;
  t_BASS23_ErrorGetCode: function: LongInt; stdcall;

  t_BASS24_Init: function(device: Integer; freq, flags: DWORD; win: HWND; clsid: PGUID): BOOL; stdcall;
  t_BASS24_SetConfig: function(option, value: DWORD): DWORD; stdcall;
  t_BASS24_MusicLoad: function(mem: BOOL; f: Pointer; offset, length, flags, freq: DWORD): DWORD; stdcall;
  t_BASS24_StreamCreateFile: function(mem: BOOL; f: Pointer; offset, length: QWORD; flags: DWORD): DWORD; stdcall;
  t_BASS24_ChannelGetLength: function(handle: DWORD; mode: DWORD): Int64; stdcall;
  t_BASS24_ChannelGetInfo: function(handle: DWORD; var info: BASS24_CHANNELINFO):BOOL; stdcall;
  t_BASS24_ChannelIsActive: function(handle: DWORD): DWORD; stdcall;
  t_BASS24_ChannelGetData: function(handle: DWORD; buffer: Pointer; length: DWORD): DWORD; stdcall;
  t_BASS24_ChannelGetPosition: function(handle: DWORD; mode: DWORD): QWORD; stdcall;
  t_BASS24_ChannelSetPosition: function(handle: DWORD; pos: QWORD; mode: DWORD): BOOL; stdcall;
  t_BASS24_ChannelBytes2Seconds: function(handle: DWORD; pos: QWORD): FLOAT; stdcall;
  t_BASS24_ChannelSetSync: function(handle: DWORD; stype: DWORD; param: QWORD; proc: SYNCPROC; user: Pointer): HSYNC; stdcall;
  t_BASS24_MusicFree: function(Channel: Cardinal): Bool; stdcall;
  t_BASS24_StreamFree: function(Channel: Cardinal): Bool; stdcall;
  t_BASS24_GetDevice: function: DWORD; stdcall;
  t_BASS24_ChannelPlay: function(handle: DWORD; restart: BOOL): BOOL; stdcall;
  t_BASS24_ChannelStop: function(handle: DWORD): BOOL; stdcall;
  t_BASS24_ChannelPause: function(handle: DWORD): BOOL; stdcall;
  t_BASS24_ErrorGetCode: function: LongInt; stdcall;

The thing is that the calls to BASS_MusicLoad() and BASS_StreamCreateFile() work, I mean they return 0 handle. And give the mentioned error code (BASS_StreamCreateFile() returns  BASS_ERROR_NOTAVAIL for an MP3 file).
The crash is coming when leaving the FD_BASS_MusicLoad() and FD_BASS_StreamCreateFile()! ???

This is the only bug left in mi program that I know of, it would be really cool if it worked! :)

Thanx for helping. Maybe a debug version of bass.dll could help? ::)
I mean why is an MP3 handle 0?

Best regards
3delite
« Last Edit: 25 Sep '09 - 17:38 by 3delite »

Xire

  • Posts: 276
You have a bug ;)

try this

t_BASS24_MusicLoad: function(mem: BOOL; f: Pointer; offset: QWORD; length, flags, freq: DWORD): DWORD; stdcall;


3delite

  • Posts: 925
You're a God Xire!
It works!
I owe you a pack of beer! :D

The right definitions:

Code: [Select]
 t_BASS23_MusicLoad: function(mem: BOOL; f: Pointer; offset, length, flags, freq: DWORD): DWORD; stdcall;
  t_BASS23_StreamCreateFile: function(mem: BOOL; f: Pointer; offset, length, flags: DWORD): DWORD; stdcall;

  t_BASS24_MusicLoad: function(mem: BOOL; f: Pointer; offset: QWORD; length, flags, freq: DWORD): DWORD; stdcall;
  t_BASS24_StreamCreateFile: function(mem: BOOL; f: Pointer; offset, length: QWORD; flags: DWORD): DWORD; stdcall;

Still have some problems though.
Works fine with BASS 2.3 (no more an issue) but BASS 2.4 returns error code 37 (BASS_ERROR_NOTAVAIL for XM) and 41 BASS_ERROR_FILEFORM (for MP3s).
What could it be?

The interesting part is that when creating the channel for playing, it works and plays all files properly.  ???

Code: [Select]
procedure TBalloonForm.ButtonBASSClick(Sender: TObject);
begin
    if fBASSChannellPlaying then begin
        //TimerBASSPlayPos.Enabled := False;
        if (NOT BASS_Available)
            then Exit;
        BASS_ChannelPause(fBASSChannel);
        fBASSChannellPlaying := False;
    end else begin
        //* Init BASS is needed
        if BASS_Available
        AND (BASS_ActiveDevice = -1)
        //AND (NOT fdSettings.BASSDontInit)
            then InitializeBASS(-1, 44100, Handle);
        //* No BASS: Exit
        if (BASS_ActiveDevice = -1)
            then Exit;
        //* Play
        if (fBASSChannel = 0)
        OR (BASS_ChannelGetPosition(fBASSChannel) = -1)
            then fBASSChannel := BASS_StreamCreateFile(False, PChar(FFileData.SolvedFileName), 0, 0, BASS_STREAM_AUTOFREE OR BASS_UNICODE);
        if fBASSChannel = 0
            then fBASSChannel := BASS_MusicLoad(False, PChar(FFileData.SolvedFileName), 0, 0, BASS_MUSIC_AUTOFREE OR BASS_UNICODE, 0);
        if BASS_ChannelPlay(fBASSChannel, False) then begin
            BASS_ChannelSetSync(fBASSChannel, BASS_SYNC_END, 0, @CallbackStreamEnd, Pointer(DWord(Self)));
            fBASSChannellPlaying := True;
            FPinButton.Down := True;
        end;
    end;
end;

This works, but this only works for the first file (?):

Code: [Select]
        if Channel = 0 then begin
            Channel := BASS_MusicLoad(FALSE, PWideChar(FileName), 0, 0, BASS_MUSIC_DECODE OR BASS_SAMPLE_FLOAT OR BASS_MUSIC_STOPBACK OR BASS_MUSIC_CALCLEN OR BASS_UNICODE OR BASS_STREAM_AUTOFREE, 0);   // BASS_SAMPLE_MONO
            if Channel = 0
                then Channel := BASS_StreamCreateFile(False, PWideChar(FileName), 0, 0, BASS_STREAM_DECODE OR BASS_SAMPLE_FLOAT OR BASS_MP3_SETPOS OR BASS_UNICODE OR BASS_STREAM_AUTOFREE);
        end;

Any more ideas, anybody?

Best regards
3delite
« Last Edit: 26 Sep '09 - 16:34 by 3delite »

3delite

  • Posts: 925
Very strange. Removed the BASS_STREAM_AUTOFREE flag and it now works. Got a valid channel handle.
Ian if you are interested to reproduce the bug I can help you with that.

Thanx for all helping!

Best regards
3delite

Ian @ un4seen

  • Administrator
  • Posts: 20774
The problem there is the combination of the DECODE and AUTOFREE flags; they can't be combined. BASS 2.3 would ignore the AUTOFREE flag in that case. That was noted in the documentation, but just to make it absolutely clear that the flags can't be combined, BASS 2.4 will produce an error (BASS_ERROR_NOTAVAIL) instead.

3delite

  • Posts: 925
Ok, clear. Thanx!  :)

Best regards
3delite