mp3 time is always too big

Started by void, 16 Jun '03 - 05:03

void

I am trying to display the length (in seconds) of the currently playing song and the time that is displayed is always larger then it's supposed to be and I don't know why. Here is the code I am using.

procedure TForm1.Button1Click(Sender: TObject);
Var
 len : QWord;
 time : Float;
begin
 len := Bass_StreamGetLength(handle);
 time := Bass_ChannelBytes2Seconds(handle,len);
 label1.Caption := FloatToStr(time);
end;

I added the BASS_MP3_SETPOS Flag to the Bass_StreamCreateFile function but it has no effect so I have no idea what I am doing wrong and hope someone here can shed some light on the situation.

I am using Delphi6 on WinXP with SP1 installed if that helps at all.

bigjim

From the bass help file->

QuoteThe exact stream length will be returned once the whole file has been streamed, until then it's not always possible to 100% accurately estimate the length of a stream, so the length returned may be only an approximation when using some WAV codecs. The length is always exact for MP3/MP2/MP1 files when the BASS_MP3_SETPOS flag is used in the BASS_StreamCreateFile call. When the BASS_MP3_SETPOS flag is not used, the length is an (usually accurate) estimation based on the file size (until the whole file has been streamed).

The length returned for OGG files will usually be exact (assuming the file is not corrupt), but for OGG files streamed from the internet (or user file stream) it can be a very rough estimation.

If you are streaming mp3s- with the _SETPOS flag how do you know that the length is incorrect. ie. what other software are you using to obtain the correct file length?

void

I am using winamp which has not failed me yet.

Also when I ran that function on one of my songs it returned a length of 237 seconds which when divided by 60 equals 3.95  ??? I mean how is that possible for a song to be 3 minutes and 95 seconds long.

Obviously something is not working as it should.

rgomez

237 seconds divided by 60 is 3.95 as you say. But not 3 minutes and 95 seconds. Is 3.95 *minutes*

To have the number of seconds you will have get the modulus of the number. In this case, 237 mod 60 is 57. So, you have 3 minutes (correctly, from the "integer" division) and 57 seconds.

Regards,

Rodrigo Gómez

void

Thanks for the help but I have one last question.

How would I modify this procedure so that it will show the time in the format Min:Sec on a label

procedure TForm1.Button1Click(Sender: TObject);
Var
len : QWord;
time : Float;
begin
len := Bass_StreamGetLength(handle);
time := Bass_ChannelBytes2Seconds(handle,len);
label1.Caption := FloatToStr(time);
end;

Sheep

procedure TForm1.Button1Click(Sender: TObject);
var
  len : QWord;
  time : Float;
  min, sec : integer;
begin
  len := Bass_StreamGetLength(handle);
  time := Bass_ChannelBytes2Seconds(handle,len);
  min := time div 60;
  sec := time mod 60;
  label1.Caption := inttostr(min) + ":" + inttostr(sec);
end;

void

Thanks Sheep but I have been trying that all day and delphi gives me an error saying "Operator not applicable to this operand type"

for the lines

min := time div 60;
and
sec := mod 60;

DanaPaul


Quotedelphi gives me an error saying "Operator not applicable to this operand type"

"Time" is a Delphi reserved word which returns a TDateTime value representing the "Time" portion of Now (TDateTime).  Try this...

procedure TForm1.Button1Click(Sender: TObject);
Var
MyLen : QWord;
MyTime : Float;
begin
MyLen := Bass_StreamGetLength(MyHandle);
MyTime := Bass_ChannelBytes2Seconds(MyHandle, MyLen);
label1.Caption := FloatToStr(MyTime);
end;

In the example above "handle" has been changed to "MyHandle" because Delphi will return the "handle" for TForm1 instead of the "Channel" that you retrived when creating the Bass Stream or Sample.

You must be careful when declaring variables that have already been used. Or instead utilize Objects and Records that allow you to specify which variable to use.  IE:  MyForm.handle vs MyBassChannel.handle.


void

Thanks again but still no go here is the code I am now using.

procedure TForm1.Button1Click(Sender: TObject);
Var
 mylen : QWORD;
 mytime : Float;
 mymin, mysec : Integer;
begin
 mylen := Bass_StreamGetLength(myhandle);
 mytime := Bass_ChannelBytes2Seconds(myhandle,mylen);
 mymin := mytime div 60;
 mysec := mytime mod 60;
 label1.Caption := inttostr(mymin) + ":" + inttostr(mysec);
end;

It does not seem to matter what I call the vars the error still occurs.

DanaPaul

#9
QuoteVar mytime : Float;
 begin
 mymin := mytime div 60;
 mysec := mytime mod 60;
 end;
It does not seem to matter what I call the vars the error still occurs.

QQps...

The code above will not compile because "MyTime" is a floating point integer type and the remaining working variables are integers.

Try this...

mymin := Round(mytime / 60);
mysec := Round(mytime) mod 60;

The following code could be used as well, but "Trunc" uses the Floating Point processor and therefore is slower than the "Round" function...

mymin := Trunc(mytime / 60);
mysec := Trunc(mytime) mod 60;

Additionally, the "Div" operand will divide 2 values and discard any remainder (similar to Trunc or Round), however, the "/" (divide) operand will divide 2 values preserving any remainder (returning a floating point value).

Please note that this response addresses your syntax (compile) errors specifically.  If you should continue to have problems calculating these stream/file values please post again.


void

Thanks alot DanaPaul I was beginning to lose my hair :)

It seems I am going to have to use trunc even though it's slower because using round adds 1 to the minutes of some songs.

In other words if I used trunc the time displays as 3:57 and if I use round it displays as 4:57 *weird*

DanaPaul


QuoteIt seems I am going to have to use trunc even though it's slower because using round adds 1 to the minutes of some songs.

In other words if I used trunc the time displays as 3:57 and if I use round it displays as 4:57 *weird*

Delphi Help file exclaims...

"Round returns a Longint value that is the value of X rounded to the nearest whole number."

An old trick that I used often in Excel spreadsheets was to add 0.5 to the value before "Round" to retrieve a result that was rounded up.  Excel would only round down. In this case subtacting 0.5 from the value would force rounding down to the nearest whole value...

mymin := Round((mytime - 0.5) / 60);

I'm sure that the "Trunc" flavor of this call will suffice, eh? :)




bigjim

#12
I use something like this- any good?

var
  len : float;
  mins : integer;
  secs : integer;
  fracs : float;
begin
  len := BASS_ChannelBytes2Seconds(handle, BASS_StreamGetLength(handle));
  mins := trunc(len / 60);
  secs :=  trunc(len-(mins*60));
  fracs := len - ((mins*60) + secs);

DanaPaul

#13
I haven't found any way to force left side padding (zero "0") with Delphi Format strings, so here's what I came up with for a Progress display...

procedure doProgressProc(F: Single);
var
  P: Cardinal;
begin
  p := Trunc(F);
Case P Mod 60 of
  0..9 : Caption := Format('%d:0%d', [P Div 60, P Mod 60]);
  10..60: Caption := Format('%d:%d', [P Div 60, P Mod 60]);
  end;

engineeer

QuoteI haven't found any way to force left side padding (zero "0") with Delphi Format strings
Delphi help >  Format strings
d      Decimal. The argument must be an integer value. The value is converted to a string of decimal digits. If the format string contains a precision specifier, it indicates that the resulting string must contain at least the specified number of digits; if the value has less digits, the resulting string is left-padded with zeros.

So, in your case it should be:
Caption := Format('%d:%2.2d', [P Div 60, P Mod 60]);

DanaPaul


QuoteSo, in your case it should be:
Caption := Format('%d:%2.2d', [P Div 60, P Mod 60]);

Thanks Engineer.  For some reason I could only get it to left pad with spaces.  I must have had a syntax error, eh? :)

Ingolf

#16
Use FormatFloat...

If I'm not mistaking, you can also get rid of the integers, because when doing:

FormatFloat('00',minutes)+':'+FormatFloat('00',seconds)

the fractions are automaticly discarded (???)
don't know, but this is a handy function...

(but Format is just as cool!)

DanaPaul


QuoteUse FormatFloat... the fractions are automaticly discarded (???)

Well, the underlying functionality of FormatFloat is that both the integer and fraction portions are converted to a string.  However, this will bring us right back to the original problem, 3.97 *minutes* instead of 3:57 (seconds), eh?

The syntax that I use for FormatFloat (fraction isn't discarded) is similar to...

Duration := FormatFloat('.000', GetDuration) + ' Sec.';

Regardless, in my humble opinion, MOD is quicker and more accurate.

On the other hand, to obtain the integer or fraction portion of a floating point value use Trunc(Float) or Frac(Float) respectively :)