Bass in Linux, Paths, Makefile, and other things – do not know what to do

Started by stephanos,

stephanos

Dear All

I am transferring all my Lazarus coding to my Linux computer.  So a programme I wrote on Windows, Lazarus 32 bit and also works in 64 bit, both with appropriate versions of bass, are working OK.

I have installed the 64 bit Debian version of Lazarus and made a new project folder for my programme, and copied the two Linux Bass files over the project file
   bass24-linux/pascal/bass.pas
   bass24-linux/libs/x86_64/libbass.so
However, the programme does not compile, stopping at this line of code:
     BASS_Init(0, 44100, 0, H, NIL);

So I did some reading: "Linux version - The LIBBASS.SO file needs to be in the OS's library search path for it to be found; simply placing it in the same directory as the executable won't necessarily work as it does on other platforms.  The BASS libraries should also not be placed in the standard library directories to avoid version conflicts. To meet those competing requirements, a wrapper script could be used to set the "LD_LIBRARY_PATH" environment variable before loading the executable.  Another option is to set the "rpath" in the executable to tell it where to look for libraries, which is what the example makefiles do.
When building for multiple architectures, it is possible to simply try linking with all LIBBASS.SO versions, and the linker will use the appropriate one and ignore the others."

I regret to say I do not know what the above means, and I do not know what to do.

Much help needed and any help appreciated

Stephanos

Ian @ un4seen

Quote from: stephanosHowever, the programme does not compile, stopping at this line of code:
    BASS_Init(0, 44100, 0, H, NIL);

Please post the error message(s) that you're getting there.

A window handle isn't needed when using the "No Sound" device, so you can put "NIL" in the BASS_Init "win" parameter. That parameter is actually only ever used with DirectSound output on Windows.

stephanos

Thanks for the response
Screen shot attached
Not sure which is the 'win' parameter? 
I substituted 'NIL' for each parameter but it did not work.
I read the error message again and I do not understand why H not a pointer?

Falcosoft

Quote from: stephanos...
I read the error message again and I do not understand why H not a pointer?

Because H is a HSTREAM (a DWORD) just as you defined and not a pointer.
This is exactly the parameter Ian was talking about. You should simply pass nil instead of H there.

stephanos

Dear All
Thanks for the help.  Amended the code to: "BASS_Init(0, 44100, 0, NIL, NIL);"
It did compile: see BassLinuxError-2.png
But did not run, see BassLinuxError-3.png
Wait to hear

Chris

why are you load bass in a while loop?
Lazarus on Linux is UTF8 Based so I don`t think the utf8encode is needed.
Creating  a stream with unicode (PWideChar) is the flag BASS_UNICODE needed.
Creating  a stream with Ansi (PAnsiChar) is without the flag BASS_UNICODE needed.

i would recommend to change something like this

OnFormCreate......
begin
  Bass_Init(......
end;

OnFormDestroy.....
begin
  Bass_Free();
end;

OnBitBtn4Click......
begin
........
  with Memo1 do
  begin
      for i := 0 to Lines.Count -1 do
      begin
         if h <> 0 then
         Bass_StreamFree(h).
         if FileExists(Lines[i]) then
           h := Bass_StreamCreateFile(false,PWideChar(Lines[i]),0,0, BASS_Stream_DECODE or BASS_UNICODE);
           if (h = 0) then // error can't load the file
           begin
            ErrorMessageString = Bass_ErrorGetCode();
            Display the Error.......   
            exit;
          end;
      end;
  end;
end;

stephanos

Dear Chris and others

The reason the bass actions are in a loop is complicated.  I have made a mental note of the alternative.

Meanwhile, the error message appears to be saying that a path to something is missing.  This has previously been mentioned in the bass help or readme file.  However, I do not know what the following means:
  "The LIBBASS.SO file needs to be in the OS's library search path for it to be found; simply
   placing it in the same directory as the executable won't necessarily work as it does on other
   platforms"
So where is the library search path? Is it a file like autoexec.bat into which I am used to adding paths to executables?

Much help still needed, I think

Ian @ un4seen

Quote from: stephanosMeanwhile, the error message appears to be saying that a path to something is missing.  This has previously been mentioned in the bass help or readme file.  However, I do not know what the following means:
  "The LIBBASS.SO file needs to be in the OS's library search path for it to be found; simply
  placing it in the same directory as the executable won't necessarily work as it does on other
  platforms"
So where is the library search path? Is it a file like autoexec.bat into which I am used to adding paths to executables?

I think it's best to set the "rpath" value in your executable to tell it where to look for the BASS libraries. I'm not familiar with how you would do this with Lazarus, but if it allows you to set linker options then add "-rpath=$ORIGIN" (or "-Wl,-rpath,$ORIGIN") there, and you can then put the BASS libraries alongside your executable (like on Windows).

stephanos

Dear All and Ian

Thanks for that.  Is this issue now best placed in a non Bass forum?

stephanos

Dear All

Chris' last post solved it.  The programme now compiles and runs with libbass.so and bass.pas in the project folder having entered a string in "Project-> Options-> Compiler Options -> Compilation and Linking -> check "Pass Optins to linker with "-k "" -> put --rpath=$ORIGIN into edit box".

Thanks to all

stephanos

Dear All

I spoke too soon.  The programme compiles and runs.  But the Bass bit is not working. 

I have a memo window containing the paths to mp3 files.  It will be written to a m3u file and function as a playlist on my mp3 player.  However, I need to find out the run time of all the audio files in the memo window first.  So one at a time I need to parse each path/ile name to Bass to find out the run time.  That is why Bass is in a loop.  However, now  am in Linux it is not working.  It was working in Lazarus under Windows.

I tried to diagnose the problem by working through the code linearly, testing just one file.

var
TotalPlayTimeInSecs, PlayTimeInSecs : QWord;  // 0 - 18446744073709551615
                                            Len_Bytes : QWord;  // for the individual file
                                              Len_Secs : Double; // for the individual file
              IsPathFNFound, MemoString : string;
                                      hour, min, sec : byte;    // 0-255
                                                          H : HSTREAM;  // used by Bass
Len_Bytes := 999;

MemoString := Memo1.Lines.Text;  // copy the memo text to a string.  I checked and it was
Tag := Pos(#10, MemoString);          // find the position of the end/new line char

The first path/file is "Planxty\Planxty\Planxty Irwin.mp3" and the position of the end/new line char is 34.  So I went further:
MemoString := Memo1.Lines.Text;  // copy the memo text to a string.  I checked and it was
Tag := Pos(#10, MemoString);        // find the position of the end/new line char
IsPathFNFound := Copy(MemoString, 1, (Tag-1)); // copy the first path/filename
Label3.Caption := IsPathFNFound ;  // validate the content of the string IsPathFNFound. 

It worked and correctly output the path/filename "Planxty\Planxty\Planxty Irwin.mp3".  So I progressed:
MemoString := Memo1.Lines.Text;  // copy the memo text to a string
Tag := Pos(#10, MemoString); // find the position of the end/new line char
IsPathFNFound := Copy(MemoString, 1, (Tag-1)); // copy the first path/filename
BASS_Init(-1, 44100, 0, NIL, NIL);
H := BASS_StreamCreateFile(FALSE, pchar(IsPathFNFound), 0, 0, BASS_STREAM_DECODE);
Len_Bytes := BASS_ChannelGetLength(H, BASS_POS_BYTE);
Len_Secs := BASS_ChannelBytes2Seconds(H, Len_Bytes);
BASS_StreamFree(H); // close the stream and free the resources
Label3.Caption := Len_Secs.ToString();  // Output was -1

Well that is daft because it is an ordinary song lasting 3 + mins.  As part of the gradual development I tested the value of "Len_Bytes := 999;" with code:
Label3.Caption := Len_Bytes.ToString();
which correctly output 999.  I placed the code before: BASS_Init(-1, 44100, 0, NIL, NIL);
and commented out all other further lines of code

I did a further test:
Len_Bytes := BASS_ChannelGetLength(H, BASS_POS_BYTE);
Label3.Caption := Len_Bytes.ToString();  // Output was -1
and commented out all other further lines of code.

It is definitely the Bass code not working and I am not knowledgeable to figure it out.  I have read some of the helpful stuff on the unforseen forum.  I even saw some old posts of mine.

Much more help needed and appreciated

stephanos

Dear All

I noticed that the path of the file is written in Windows, with a \
     "Planxty\Planxty\Planxty Irwin.mp3"

I amended the path to Linux:
     "Planxty/Planxty/Planxty Irwin.mp3"

All the output was the same

Chris

Your Code is a little bit strange.

and you are not using Bass_ErrorGetCode()
e.g
if not BASS_Init(-1, 44100, 0, NIL, NIL)
   ShowMessage('Init-Error '+Bass_ErrorGetCode().toString)
else begin
   H := BASS_StreamCreateFile(FALSE, pchar(IsPathFNFound), 0, 0, BASS_STREAM_DECODE);
   if (H = 0)
     ShowMessage('StreamCreationError '+Bass_ErrorGetCode().toString);
end;
   

stephanos

Dear Chris

Not sure what you are trying to tell me.  The 2 out of 6 lines of code you are showing me:
"BASS_Init(-1, 44100, 0, NIL, NIL)" and "H := BASS_StreamCreateFile(FALSE, pchar(IsPathFNFound), 0, 0, BASS_STREAM_DECODE);"
are the same code I use.

You are placing them into an if so as to generate an error code.  Since you and I are using the same code, can you be more direct and tell me how to improve my code.  I can learn about error handling another time.

Moreover, you do not explain why my code is a bit strange.

Wait to hear

stephanos

Dear Chris

I got a friend to read all of this issue and your last suggestion.  He laughed at me.  It seems you are suggesting that I put code into an if to generate an error message.  I thought he was being silly, but I did it.

This code:
    if not BASS_Init(-1, 44100, 0, NIL, NIL) then
    begin
        Label3.Caption := Bass_ErrorGetCode().toString; // output: 14
    end
    else
    Begin  end; 
produces an output of 14 and not zero.  Nice bit of error checking.  I will incorporate error checking into the code as well.

So, thanks for the suggestion.  I have enacted that suggestion.  I now have new information.  The first piece of Bass code gives error 14. 

Are we back at the path issue?  Let me summarize what I have done about the path issues:
1)  In Linux, bass.pas and libbass.so are required (bass.dll not required)
2)  They can be placed in project folder but then you must do the following:
a. Instruct that project folder to be checked for a library.  In Lazarus.  Go to Project-> Options-> Compiler Options -> Compilation and Linking -> Tick "Pass Options to linker with "-k "", and type "-rpath=$ORIGIN" into edit box.  Before I completed this task, the programme would compile but not run.  After completing the task the programme runs, but when I press the button to use Bass to read data from the mp3 files, Bass has produced error:
    "14  BASS_ERROR_ALREADY"

Any further help needed

Chris

Yes take a look @ my first post.

OnFormCreate......
begin
  Bass_Init(......
end;


OnFormDestroy.....
begin
  Bass_Free();
end;

after that just remove your bass_init calls from your loop code.

Error 14 will mean Bass was already init;

and just check if the Filename exists.
e.g
if FileExists(IsPathFNFound)then
    H := BASS_StreamCreateFile(FALSE, pchar(IsPathFNFound), 0, 0, BASS_STREAM_DECODE);
    if H <> 0 then
    begin
      do your stuff 
    end else
    begin
    // Error Checking
       ShowMessage('StreamCreationError '+Bass_ErrorGetCode().toString);
    end;
 

stephanos

Greeting all

I have been preoccupied with other things and now return to this tricky issue.  The agenda has changed a bit since I last posted so I am going to start again

I am transitioning a Windows programme to Linux.  I run the programme, I click a button. I select a playlist file, ending .M3U, which is on an MP3 player, that has a FAT 32 file structure.  The string that holds the path/filename.M3U is global as it will be needed later with other OnClick events.  It reads in the content of the M3U file into a memo window.  Each line is a paths/filenames.mp3 on that player.  The memo content is written in DOS format, notice the backslash.  When the player is disconnected from a PC and the playlist file is started, that is the structure the player is looking for, a backslash.  Below is the content of the M3U file and therefore the memo text as well
QuoteAlasdair Roberts\Farewell Sorrow\Farewell Sorrow.mp3
Didgeridoo Dreaming - Aboriginal Spiritual Music 1\The First Kangaroo.mp3
Donald Fagen\The Nightfly\Track 02.mp3
Agua de Pena\ROMARIAS\BAILE DA NOITE.mp3

The intention is to get the play time for each path/file.mp3.  So far it is not working, and it is another button/OnClick event.  This task lends itself to an iteration but I have made it linear so as to find the point where the code does not work.  This is what I have so far:

The programme is being run from the Linux computer with bass.pas and libbass.so in the same folder.

Var
IsPathFNFound, IsPathFNFound2, MemoString : string;  // MemoString gets reused
                                Len_Bytes : UInt64;  // used by BASS to get the bytes
                                 Len_Secs : Real;    // used by BASS to get the seconds
                                        H : HSTREAM; // used by BASS   
begin
MemoString := Memo1.Lines.Text; // Copy the content of Memo.Text into string: MemoString.

// change the \ to / 
MemoString := StringReplace(MemoString, '\', '/', [rfIgnoreCase, rfReplaceAll]);
// Copy the global string: m3uPathFile, into a local string
IsPathFNFound2 := m3uPathFile;
IsPathFNFound2 := ExtractFilePath(IsPathFNFound2); // reduce it to the path not file name
// Test that I have the path to the Music folder on the MP3 player.  The M3U file is also in Music
Label3.Caption := IsPathFNFound2; // The output was: "/media/stephanos/Sport Go/Music/"

// Now add a path/filename.mp3 to the string path
Tag := Pos(#10, MemoString); // Tag is 0 at start.  Pos returns zero if not found
IsPathFNFound := Copy(MemoString, 1, (Tag-1));  // find the first mp3 file
// I tested to make sure I had a correct path/filename.mp3
//Label3.Caption := IsPathFNFound; // "Alasdair Roberts/Farewell Sorrow/Farewell Sorrow.mp3"
// Add the path/filename.mp3 to the path
IsPathFNFound2 := concat(IsPathFNFound2, IsPathFNFound);
//  I checked I had a full correct path/filename
//Label3.Caption := IsPathFNFound2;  // "/media/stephanos/Sport Go/Music/Alasdair Roberts/Farewell Sorrow/Farewell Sorrow.mp3"
// Now to apply BASS to it
BASS_Init(0, 44100, 0, NIL, NIL);
H := BASS_StreamCreateFile(FALSE, pchar(Utf8Encode(IsPathFNFound)), 0, 0, BASS_STREAM_DECODE);
Len_Bytes := BASS_ChannelGetLength(H, BASS_POS_BYTE);
//Label3.Caption  := IntToStr(Len_Bytes);  // 18447644073709551615 works.  So I went further
Len_Secs := BASS_ChannelBytes2Seconds(H, Len_Bytes);
Label3.Caption  := FloatToStr(Len_Secs); // "-1"

Well getting the length in Bytes worked but
Len_Secs := BASS_ChannelBytes2Seconds(H, Len_Bytes); returned an error -1, BASS_ERROR_UNKNOWN

In addition, when the length in seconds is stored in a double:
Len_Secs : Double ;
The error is the same

Much help needed, any help appreciated

Falcosoft

Quote from: stephanos...
Len_Bytes := BASS_ChannelGetLength(H, BASS_POS_BYTE);
//Label3.Caption  := IntToStr(Len_Bytes);  // 18447644073709551615 works.  So I went further
Len_Secs := BASS_ChannelBytes2Seconds(H, Len_Bytes);
Label3.Caption  := FloatToStr(Len_Secs); // "-1"[/code]

Well getting the length in Bytes worked but
Len_Secs := BASS_ChannelBytes2Seconds(H, Len_Bytes); returned an error -1, BASS_ERROR_UNKNOWN

In addition, when the length in seconds is stored in a double:
Len_Secs : Double ;
The error is the same

Much help needed, any help appreciated

Are you sure that the BASS_ChannelGetLength() call actually works and gives a correct result?
Do yourself a favor and write down that result in 3 digit groups:
18 447 644 073 709 551 615

This length in bytes is in the exabyte range (millions of gigabyte) which does not seem right for an mp3 file...

Chris

Are you shure that this call is correct?
QuoteH := BASS_StreamCreateFile(FALSE, pchar(Utf8Encode(IsPathFNFound)), 0, 0, BASS_STREAM_DECODE);

just try this

H := BASS_StreamCreateFile(FALSE, pchar(IsPathFNFound), 0, 0, BASS_STREAM_DECODE OR BASS_UNICODE);and by the way just check what Bass_ErrorGetCode() return after the Bass_StreamCreateFile Call.