Delphi: load BASS DLL and play MP3
Asked Answered
U

3

6

I want to load a bass dll manually from somewhere and then play a mp3 file. How to do that? Delphi XE2.

My attempt doesn't work:

type
  QWORD = Int64;
  HSTREAM = LongWord;
type
  TBASS_ChannelPlay = function(handle: HSTREAM; restart: LongBool): LongBool; stdcall;

type
  TBASS_StreamCreateFile = function(mem: LongBool; f: Pointer;
    offset, length: QWORD; flags: LongWord): HSTREAM; stdcall;

procedure PlayMP3(FileName: string);
var
  BASS_ChannelPlay: TBASS_ChannelPlay;
  BASS_StreamCreateFile: TBASS_StreamCreateFile;
  DllHandle: THandle;
  MP3Stream: HSTREAM;
  DllPath:string;
  pFileName:pchar;
begin
  DllPath:= 'c:\dll\bass.dll';
  DllHandle := LoadLibrary(pchar(DLLPath));
  try
    if DllHandle = 0 then
      Exit;
    @BASS_StreamCreateFile := GetProcAddress(DllHandle,
      'BASS_StreamCreateFile');
    if @BASS_StreamCreateFile <> nil then
    begin
      pfilename:=pchar(FileName);
      MP3Stream := BASS_StreamCreateFile(false, Pfilename, 0, 0, 0);
      if MP3Stream <> 0 then
      begin
        @BASS_ChannelPlay := GetProcAddress(DllHandle, 'BASS_ChannelPlay');
        if @BASS_ChannelPlay <> nil then
          BASS_ChannelPlay(MP3Stream,false);
      end;
    end;
  finally
    FreeLibrary(DllHandle);
  end;
end;

But BASS_StreamCreateFile returns 0 all time :(

The code from their example (Bass Test) and Bass.pas:

type
  DWORD = LongWord;
  BOOL = LongBool;
  QWORD = Int64;
  HSTREAM = DWORD;

function BASS_StreamCreateFile(mem: BOOL; f: Pointer; offset, length: QWORD; flags: DWORD): HSTREAM; {$IFDEF WIN32}stdcall{$ELSE}cdecl{$ENDIF}; external bassdll;

strs: array[0..128] of HSTREAM;

procedure TForm1.Button15Click(Sender: TObject);
var
    f: PChar;
begin
    if not OpenDialog2.Execute then Exit;
    f := PChar(OpenDialog2.FileName);
    strs[strc] := BASS_StreamCreateFile(False, f, 0, 0, 0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
    if strs[strc] <> 0 then
    begin
        ListBox3.Items.Add(OpenDialog2.FileName);
        Inc(strc);
    end
    else
        Error('Error creating stream!');
end;

Added

  MP3Stream := BASS_StreamCreateFile(false, Pfilename, 0, 0, 0);
  ShowMessage(SysErrorMessage(GetLastError));

GetLastError doesn't show any errors!

Added

There is BASS 2.4 Delphi unit (dynamic) too.

It's written:

How to install Copy DYNAMIC_BASS.PAS to the \LIB subdirectory of your Delphi path or your project dir Call Load_BASSDLL (eg. in FormCreate) to load BASS before using any functions, and
Unload_BASSDLL (eg. in FormDestory) to unload it when you're done.

NOTE: Delphi 2009 users should use the BASS_UNICODE flag where possible

I do:

 if Load_BASSDLL(DllPath) then
  begin
  FileName:='C:\Users\V\Desktop\cmd.mp3';
  MP3Stream:=BASS_StreamCreateFile(False, pchar(FileName), 0, 0, 0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
    if MP3Stream <> 0 then
     BASS_ChannelPlay(MP3Stream, False);
     Unload_BASSDLL;
  end;

It still doesn't work :(

Added:

If to do

BASS_Init(-1, 44100, 0, Form1.Handle, nil);

then BASS_ChannelPlay(MP3Stream, False) returns true but I don't hear a sound:(

Uribe answered 22/1, 2012 at 20:38 Comment(1)
Again, read my edited answer. If you look at dynamic_bass.pas, especially the code for Load_BASSDLL, it does NOT call BASS_Init. It simply loads the library and does all of the GetProcAddress calls.Competent
C
8

You're missing the call to BASS_Init. From the same demo you quoted from, in the FormCreate event:

// Initialize audio - default device, 44100hz, stereo, 16 bits
if not BASS_Init(-1, 44100, 0, Handle, nil) then
  Error('Error initializing audio!'); 

Also, look at the demo source's call:

BASS_StreamCreateFile(False, f, 0, 0, 
 0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});

Note what happens with the last parameter? The or BASS_UNICODE is required on D2009 and up, unless you're using PAnsiChar instead of PChar; Delphi's default string type is UnicodeString, and the default PChar is PWideChar.

You can use it with the {$IFDEF UNICODE} or without it; Delphi defines UNICODE, so if you use it your code will be backwards-compatible with earlier versions of Delphi (pre-D2009) as well.

You should also look at dynamic_bass.pas in the Bass\Delphi\dynamic folder. It has code to dynamically load the library and retrieve all the functions; if you don't want to use it directly, at least you could copy the function definitions and dynamic loading code you need from there instead.

Competent answered 22/1, 2012 at 21:15 Comment(9)
I added or $80000000 (BASS_UNICODE const), BASS_StreamCreateFile returns "0"Uribe
Where are you trying to create the file (what filename)? What Windows version are you using? Is this a 32 or 64 bit project?Competent
A file path is "c:\users\v\desktop\1.mp3"; Windows 7 x32; 32 bit project.Uribe
I don't know what else it might be, then. I really don't understand why you're making it so complicated for yourself, though; you have a perfectly good demo that you could just copy and paste code from and then remove the references the the OpenDialog and ListBox from and change to accepting the filename as a parameter. You also insist on doing things like hard-coding constants that are already defined (BASS_UNICODE, but you hard-coded $80000000 instead of just using it), and manually loading the DLL and using GetProcAddress instead of just statically loading it.Competent
The DLL mustn't be in application's folder because it's a single-file application (only EXE). I don't want to keep the program on a desktop with the DLL (but somewhere in a temporary folder). It's not a big project with many many files, including DLLs, where keeping them with EXE is normal.Uribe
And the most main - I will use the DLL very rarely! I don't need Static Loading (it's not a player).Uribe
Fair enough. See my edited answer. (I just downloaded Bass 2.4 from the link you gave, unzipped it into a folder, opened BTMain.pas in Notepad++, and glanced at the code.)Competent
Thanks, it works!!! BASS_ChannelPlay(MP3Stream, False) return true...but I don't hear a sound :(Uribe
You could accept my answer, then. :) Not hearing a sound is a separate question; this one (with all your edits and the comment discussion) has become pretty noisy.Competent
R
2

Suggestion - just don't load the .dll manually. Forget "LoadDll" and ESPECIALLY forget all that grungy, low-level Win3.0 era "GetProcAddress()" nonsense.

Just declare an external, just like the working Bass sample code successfully does:

function BASS_StreamCreateFile(
           mem: BOOL; 
           f: Pointer; 
           offset, length: QWORD; 
           flags: DWORD): HSTREAM; 
{$IFDEF WIN32}stdcall{$ELSE}cdecl{$ENDIF}; external bassdll;

PS: If you really, really, REALLY insist on LoadDll () and friends, then:

  1. Remember that Delphi XE strings are now 16-bit Unicode

  2. Check GetLastError () to determine exactly WHY LoadDll returned a null handle.

PPS:

Rang answered 22/1, 2012 at 21:10 Comment(0)
S
0

Here is an example to use bass.dll http://delphimagic.blogspot.com.es/2013/05/escuchar-la-radio-por-streaming.html

Sitter answered 22/5, 2013 at 18:26 Comment(3)
Since your website is in spanish and this is an english-based site, consider explaining how to get the source code (if someone doesn't understand spanish is going to be a bit difficult).Deferral
Hi, welcome to SO. It is often a good idea to post a concise code fragment instead of linking to external resources for several reasons: (1) the external resource may disappear in the future, rendering your answer void (2) typically, links contain too much irrelevant information which may confuse people.Pectoralis
A link to a solution is welcome, but please ensure your answer is useful without it: add context around the link so your fellow users will have some idea what it is and why it’s there, then quote the most relevant part of the page you're linking to in case the target page is unavailable. Answers that are little more than a link may be deleted.Competent

© 2022 - 2024 — McMap. All rights reserved.