Recent

Author Topic: Accessing File Properties  (Read 3528 times)

stephanos

  • New Member
  • *
  • Posts: 22
Accessing File Properties
« on: October 24, 2021, 07:30:46 pm »
Dear All

I am developing further features to my MP3 playlist writing programme using Lazarus 2.0.8.  The programme lives on the player.  So far I can select a number of files (that are on the player) and write them into a Memo, do a little bit of editing, and save the Memo content to the M3U file that is also on the player.

I will also write a feature to perform validation on the path/filenames as the Play List feature of the MP3 player only reads file names with characters of 1 Byte and between ALT+32-255, 256-275, 278-287.  An interesting limitation of the Player.

I am thinking ahead and will need to add another feature.  I want to add up the play time of each MP3 file that is in the Memo.  That way I will know if I have enough music to last the journey.

I have done some searches but cannot find anything that I understand.  What do I enter in Uses?  If someone can give the names of functions I can go looking.  So far, and with the help of this forum, I have been capturing multiple names of files using FileNameEdit1Change, and writing all the selected paths/file names to a string:
     
Code: Pascal  [Select][+][-]
  1. TheFileName := FileNameEdit1.DialogFiles.Text;

But I am sure that is not the way to go as I now want system information in the form of file properties, namely “Length”.

So here I am again, any help welcomed, but remember I do not know much

Thanks

Stephanos
Using Windows 10

jamie

  • Hero Member
  • *****
  • Posts: 5050
Re: Accessing File Properties
« Reply #1 on: October 24, 2021, 07:49:33 pm »
use "FileSize" or "FindFirst" for each name string in the list.

if using findfirst make sure you close the search record before starting the next file name to search..

The FindFirst has information about the file, size, date etc.
The only true wisdom is knowing you know nothing

stephanos

  • New Member
  • *
  • Posts: 22
Re: Accessing File Properties
« Reply #2 on: October 24, 2021, 11:47:37 pm »
Dear Jamie

Thanks.  I went here:
https://www.freepascal.org/docs-html/rtl/sysutils/findfirst.html
to research FindFirst.  The properties this function can detect are read-only, a system file, a directory, and hidden.  Moreover, I will not need to search a TsearchRec as I want to selected a file using FileNameEdit1Change.  Having selected it the path/filename is written to a string. At that stage I want to extract the data for the files property: Length, add that to a total etc.

If I can do this for one file I am sure I can then teach myself how to do it for multiple files selected at the same time.

Any further help appreciated

Stephanos

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1700
  • Former Delphi 1-7, 10.2 user
Re: Accessing File Properties
« Reply #3 on: October 25, 2021, 12:15:22 am »
See FpFstat for file properties.

Lazarus 2.3, FPC 3.3.1 macOS 12.0.1 x86_64 Xcode 13.1
Lazarus 2.3, FPC 3.3.1 macOS 12.0.1 aarch64 Xcode 13.1
Lazarus 2.3, FPC 3.2.2 FreeBSD 13.0 amd64 VM
Lazarus 2.3, FPC 3.2.2 FreeBSD 12.2 amd64 VM
Lazarus 2.1 r61574 FPC 3.0.4 Ubuntu 20.04 VM
Lazarus 2.0.10 FPC 3.2.0 Win10 VM

Zvoni

  • Hero Member
  • *****
  • Posts: 808
Re: Accessing File Properties
« Reply #4 on: October 25, 2021, 08:54:46 am »
Since he wants the playing time:
https://stackoverflow.com/questions/1065086/duration-of-an-mp3-wav-audio-file

The "hard" way would be to use the ffmpeg-libs and read the duration directly
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

MarkMLl

  • Hero Member
  • *****
  • Posts: 3537
Re: Accessing File Properties
« Reply #5 on: October 25, 2021, 09:00:12 am »
See FpFstat for file properties.

Or FileSize(), or FpStat(). Note the distinction between functions which require an opened file, and those which operate on the name.

This should really be a question about how to use the "See also" link near the bottom of most documentation pages, or the indexing links presented at the top.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

BobDog

  • Full Member
  • ***
  • Posts: 170
Re: Accessing File Properties
« Reply #6 on: October 25, 2021, 06:22:20 pm »

Regarding:
"I am thinking ahead and will need to add another feature.  I want to add up the play time of each MP3 file that is in the Memo"
...
Windows using mcisendstring-- duration
and using filesize -- size in bytes (same as file -properties)
Code: Pascal  [Select][+][-]
  1.  function mciSendString(s:ansistring;p1:pointer;p2:longword;p3:longword):integer;cdecl external 'Winmm.dll' name 'mciSendStringA' ;
  2.    
  3.     function _filesize(_file:string):int64; //standard filelength in bytes
  4.      var
  5.         f:file of byte;
  6.         begin
  7.         AssignFile(f,_file);
  8.         Reset(f);
  9.         _filesize:=FileSize(f);
  10.         close(f);
  11.         end;
  12.    
  13.    
  14.     function mp3length(_file:string):int64;
  15.       type
  16.     chars = array[0..50] of char;
  17.     var
  18.     open,lngth,finish:ansistring;
  19.     length:chars;
  20.     tmp:integer;
  21.     l:int64;
  22.     begin
  23.      open:= 'open  '+_file+' type mpegvideo alias file1' ;
  24.       finish:= 'close file1';
  25.      mciSendString(pchar(open), nil, 0, 0);
  26.      lngth:= 'status file1 length';
  27.      mciSendString(pchar(lngth),@length, 50,0) ;
  28.      val(length,l,tmp);
  29.        mciSendString(pchar(finish),nil, 0, 0);
  30.      exit(l);
  31.     end;
  32.    
  33.     var
  34.     myfile:ansistring='C:\Users\Computer\Desktop\fb\pascal\mystuff\country.mp3'; //<<----- put in your path here.
  35.  
  36.  
  37.   begin
  38.  
  39.   writeln('mcisendstring method  = ', mp3length(myfile));
  40.   writeln('filesize method       = ' ,_filesize(myfile));
  41.   writeln('Press enter to end . . .');
  42.   readln;
  43.   end.
  44.  
Win 10 64 bits.
fpc 3.2.2
geany ide

stephanos

  • New Member
  • *
  • Posts: 22
Re: Accessing File Properties
« Reply #7 on: December 01, 2021, 12:26:16 pm »
Dear All

I have been steered in the direction of a plugin called Bass.  It might work.  I have joined the Unforseen forum for Bass and have received some help.  But it is pitched too high and I am struggling.  My Bass posts are dominated by one person who will not/cannot answer a straight question, so for the time being I am trying here again.  It is to be found here:
https://www.un4seen.com/forum/?topic=19590.msg137071;topicseen#msg137071

I have placed copies of bass.pass and bass.dll in the project file along with the mp3 I am practising on: BAILE MINHA MADEIRA.mp3

With some help I have adopted this solution and it compiles:
Code: Pascal  [Select][+][-]
  1. program Project1; //
  2. {$mode objfpc} {$H+}
  3. uses
  4.   bass, FileCtrl, StdCtrls, Graphics, Controls, Classes, SysUtils, LResources, Forms, Dialogs,
  5.   Interfaces;
  6. var
  7.                  EC : integer; H : HSTREAM; Info : BASS_CHANNELINFO; FloatLen : double;
  8.         L_Bytes : QWORD;  // length in bytes
  9.     L_Seconds : double;     // length in seconds
  10.         FBitrate : single;       //
  11.  
  12. begin
  13.      // File size is 2469 KB = 2,528,256 Bytes = 20,226,048 bits
  14.           H := BASS_StreamCreateFile(FALSE, pchar(Utf8Encode('BAILE MINHA MADEIRA.mp3')), 0, 0, BASS_STREAM_DECODE);
  15.       //
  16.      writeln('H = ', H);  // Output: zero
  17.      BASS_ChannelGetAttribute(H,BASS_ATTRIB_BITRATE, FBitrate); //
  18.      writeln('The bit rate is = ', FBitrate); //  Output: 0.000000000E+00
  19.      if (H <> 0) then // when H is equal to zero  the stream is not opened
  20.      begin
  21.             L_Bytes := BASS_ChannelGetLength(H, BASS_POS_BYTE); // length in bytes
  22.             writeln(L_Bytes); // -1
  23.           L_Seconds := BASS_ChannelBytes2Seconds(H, L_Bytes);   // convert bytes to seconds
  24.           writeln('True, number of seconds = ', L_Seconds);     // Output  -1
  25.           EC := BASS_ErrorGetCode();  write('Error Code = ', EC);  // Output
  26.      end
  27.      else
  28.      begin
  29.           writeln('False = H is ', H);     // False = H is 0
  30.           EC := BASS_ErrorGetCode();  writeln('Error Code = ', EC);
  31.           writeln(); writeln(); //
  32.      end;
  33.      BASS_StreamFree(H); // close the stream and free the resources  {**}
  34.      readln();
  35. end.


There appear to be a problem.  The value of H is always zero.  At first I thought this value was one of the error codes found here: https://www.un4seen.com/doc/#bass/BASS_ErrorGetCode.html
At first I thought that the zero in this list (BASS_OK ) was the same as the value in H.  Although no one from the forums has put me straight.  I am proceeding on the basis that they are two different values.  H is zero if the stream fails to open.  Assuming this is correct then my problem is that the stream to the MP3 files fails to open.  The problem might be with this line:
Code: Pascal  [Select][+][-]
  1. H := BASS_StreamCreateFile(FALSE, pchar(Utf8Encode('BAILE MINHA MADEIRA.mp3')), 0, 0, BASS_STREAM_DECODE);

I have a little knowledge of pointers.  So could it be: pchar() not working.  Does pchar have to assign to a variable?  Something like:
Code: Pascal  [Select][+][-]
  1. pc : pchar;
  2. pc := pchar('BAILE MINHA MADEIRA.mp3');
so changing the stream to:
Code: Pascal  [Select][+][-]
  1. H := BASS_StreamCreateFile(FALSE, pc, 0, 0, BASS_STREAM_DECODE);

I tried the above and it compiled but H was still zero.
Have I not integrated Bass into Lazarus properly?

The output looks as though the stream has not opened and data has not been read.

Any help appreciated and hopefully understood

Jorg3000

  • New member
  • *
  • Posts: 7
Re: Accessing File Properties
« Reply #8 on: December 01, 2021, 12:46:22 pm »
If you need the extended properties of a media file, e.g. the playing time, look at this example
https://stackoverflow.com/questions/66803770/get-image-dimensions-without-loading-using-meta-data

Fred vS

  • Hero Member
  • *****
  • Posts: 2514
    • StrumPract is the musicians best friend
Re: Accessing File Properties
« Reply #9 on: December 01, 2021, 12:54:16 pm »
Hello.

If you dont have luck with other propositions, you may try uos.
There are plenty of demos in /uos/examples/ for Lazarus that work out-of-the-box.

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs

dbannon

  • Hero Member
  • *****
  • Posts: 1680
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Accessing File Properties
« Reply #10 on: December 01, 2021, 01:25:41 pm »

stephanos, to be honest, it appears to me that "Chris" has given you some pretty detailed and complete answers. I suggest you go back and have a further look at using Bass.

Chris suggested a loop because thats how most repetitive tasks are handled in computers generally. Reading the details of each file is a repetitive task.

Its often hard to read code that new to you, have a read of Chris's code, line by line, understand what each line is doing and only then try to think of it as comple 'function'. There are a identifier names there that are probably described in Bass's documentation.

Good luck.

Davo
Lazarus 2, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng

stephanos

  • New Member
  • *
  • Posts: 22
Re: Accessing File Properties
« Reply #11 on: December 01, 2021, 02:43:45 pm »
Dear Davo et al

I made mention of the Bass forum in case someone mentioned taking my question there.  Also I think it showed that I have read, researched and learnt - a little.  Combined with the code, I submitted here, I think that was the next reasonable thing I could do.

Well Chris has probably given me some pretty detailed and complete answers. But I do not understand it so what else can I do except ask questions.  Then what else should I do when direct questions are are not answered.  It is not my fault I do not know something and it is no ones faulty that I do not understand.  But really what else should I do?  To go back and read it again without the benefit of an explanation is not going to work.  So I moved on.  I came up with my best guess and submitted it here. 

Moreover, as you understand what each line is doing please can you:
a) answer question 2 and 3 in the earlier posts on that forum.  These represent a genuine request to confirm potential knowledge and I do not feel they have been answered in a clear cogent way.  If
Code: Pascal  [Select][+][-]
  1. L_Seconds := BASS_ChannelBytes2Seconds(H, L_Bytes);
is taking a file size and embedded bitrate and calculating a play time in seconds then I do not need
Code: Pascal  [Select][+][-]
  1. BASS_ChannelGetAttribute(H,BASS_ATTRIB_BITRATE, FBitrate);
It would be nice to know.  Any idea? 
b) Where do you stand on my analysis/guess that there is a fault in the code:
Code: Pascal  [Select][+][-]
  1. H := BASS_StreamCreateFile(FALSE, pchar(Utf8Encode('BAILE MINHA MADEIRA.mp3')), 0, 0, BASS_STREAM_DECODE);
Do I need to declare a pointer or is it not the problem?
What is the problem?

I have submitted code very similar to Chris and as best as I understand.  Please can this forum deal with my code issue.  I am not looking for someone to do it for me.  I am trying to learn, hence the questions which remain unanswered.

I have heard mention of UOS before and I will pursue it.  I will look at  extended properties of a media file as well - thanks

patiently yours

BobDog

  • Full Member
  • ***
  • Posts: 170
Re: Accessing File Properties
« Reply #12 on: December 04, 2021, 12:44:10 am »

Bass.dll is 32 bits (I could find)
I have experimented a little, i don't have the bass unit, so I use the 32 bit bass.dll directly.
https://www.mediafire.com/file/ujbymhyc54rhfyc/basstest.zip/file

 

TinyPortal © 2005-2018