time elapsed / remaining problem

Started by breakpoint, 27 Jun '03 - 03:32

breakpoint

I am having problems displaying the elapsed and reamining time on my mp3 streams using the code below. The problem is that sometimes the elapsed and remaining times do not equal the total time for the song.

Here is an example:

Elapsed 0:10
Remaining 1:20
-------------------
Total: 1:31

and as you can see there is a 1 second differnce between what it shows and what the real value is.

I think the problem is in the code that shows the remaining time because sometimes when I start the song the remaining time is 1 second less then it should be but other times it shows the correct number so again I am not sure what needs to be done to fix this problem and any help would be great.

Here is the code I am using.
procedure TForm1.Timer2Timer(Sender: TObject);
 var
fillen : Qword;
filtime, curtime, rtime : float;
emin, esec, rmin, rsec : integer;
begin
Progressbar1.Position := BASS_ChannelGetPosition(song); // move slider if song playing

{get total time}
fillen := Bass_StreamGetLength(song);
filtime := Bass_ChannelBytes2Seconds(song,fillen);

{get elapsed time}
curtime := Bass_ChannelBytes2Seconds(song, Bass_ChannelGetPosition(song));
emin := trunc(curtime / 60);
esec := trunc(curtime) mod 60;

{get remaining time}
rtime := (filtime - curtime);
rmin := trunc(rtime / 60);
rsec := trunc(rtime) mod 60;

{show elapsed time on a label}
if esec < 10 then label8.Caption := inttostr(emin) + ':0' + inttostr(esec)
else
label8.Caption := inttostr(emin) + ':' + inttostr(esec);

{show remaining time on a label}
if rsec < 10 then label6.Caption := inttostr(rmin) + ':0' + inttostr(rsec)
else
label6.Caption := inttostr(rmin) + ':' + inttostr(rsec);
end;

DanaPaul

I would think that the problem lies in the "Trunc" action on both sets of time values.  Both sets of time values are effectively rounded down.

Try changing this...

rmin := trunc((rtime / 60) + 0.5);
rsec := trunc(rtime + 0.5) mod 60;

Or...[/i]

rtime := (filtime - curtime) + 0.5;



breakpoint

Thanks for the reply dana but that does not seem to help. infact it adds (in alot of cases) a minute to the rmin value which is no good.

As I said before this problem seems to be random which means that sometimes the rsec value shows up correctly and at other times it does not (on the exact same song) so again I am stumped because to me if it works once it should work all the time.

I am using the BASS_MP3_SETPOS flag when I create the stream so i'm pretty sure that part is working as it should.

Again any help on this would be great thx.

Creadig

works fine for me. If it helps you... here`s my code. is in VB 6.0

The Code:
PosTime = Stream01GetPosition(1)  'get the position in time (seconds)
LenTime = Stream01GetLen(1)       'get the lenght in time (seconds)
PosByte = Stream01GetPosition(2)  'get the position in bytes
LenByte = Stream01GetLen(2)       'get the lengh in bytes

'get the type of visualization in config file (normal o restante)
If TopMenu.LType.Caption = "Normal" Then
   Rst1 = ConvSecToMin(PosTime)
   Call SetDigClock(Rst1, 1, "Normal")     'Set the digital clock for display
Else
   RestTime = LenTime - PosTime
   Rst1 = ConvSecToMin(RestTime)
   Call SetDigClock(Rst1, 1, "Restante")
End If

If TopMenu.OType.Caption = "Normal" Then
   Rst2 = PosByte
   Call SetDigNum(Trim(Rst2), 1, "Normal")    'Set the digital clock for display
Else
   RestTime = LenByte - PosByte
   Rst2 = Trim(Str$(RestTime))
   Call SetDigNum(Trim(Rst2), 1, "Restante")
End If

'positions from advanced mode
Est01.E1Pos.value = PosTime
Est01.E1Pos.ToolTipText = ConvSecToMin(CDbl(Est01.E1Pos.value))
Est01.LblCurrent.Caption = ConvSecToMin(PosTime)
Est01.LblCurrByte.Caption = PosByte

'----------------------------------------
'----------------------------------------
Function Stream01GetPosition(ByVal WTypeDisplay As Long) As Long

Dim PosByte As Long
Dim PosTime As Long

PosByte = BASS_ChannelGetPosition(Strm1)
PosTime = CLng(BASS_ChannelBytes2Seconds(Strm1, PosByte))

Select Case WTypeDisplay
   Case 2
      Stream01GetPosition = PosByte
   Case 1
      Stream01GetPosition = PosTime
End Select

End Function

Chris

#4
I see you writen you code in delphi..I show my component that i have writen myself
Here the code vor the component
-----------------------------------------------------------
unit CSTTimeDraw;

interface

uses
  Windows, Messages, SysUtils, Classes,CSTBitmapLEDDigit;

type
  TCSTTimeDraw = class(TComponent)
  private
  fSlider : TCSTBitmapSlider;
  fHour,fMin,fSec,fMsec : TCSTBitmapLEDDigit;

  /// front LEDS;
  front_Hour,front_min,front_sec,front_msec : Integer;
  back_hour , back_min,back_sec ,back_msec  : Integer;
  procedure DrawTimeFront;
   procedure DrawTimeBack;
   procedure TimeDecode(Time: Longint; var Hour, Min, Sec, MSec: Word);


    { Private-Deklarationen }
  protected
    { Protected-Deklarationen }
  public
    { Public-Deklarationen }

   procedure DrawTime (back : Boolean);
   procedure Execute;

  published
  property Slider : TCSTBitmapSlider    read fslider write fslider;
  property Hour   : TCSTBitmapLEDDigit read fHour   write fHour;
  property Min    : TCSTBitmapLEDDigit read fMin    write fMin;
  property Sec    : TCSTBitmapLEDDigit read fSec    write fSec;
  property Msec   : TCSTBitmapLEDDigit read fMsec   write fMsec;



    { Published-Deklarationen }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('CST-Tools', [TCSTTimeDraw]);
end;
procedure TimeDecode(Time: Longint; var Hour, Min, Sec, MSec: Word);
Var
   MinCount, MSecCount: Word;

begin
   if Time > 0 then
   begin
     DivMod32(Time, 60000, MinCount, MSecCount);
     DivMod32(MinCount, 60, Hour, Min);
     DivMod32(MSecCount, 1000, Sec, MSec);
   end
   else
   begin
      Hour := 0;
      Min := 0;
      Sec := 0;
      MSec := 0;
   end;
end;procedure TCSTTimeDraw.DrawTimeFront;
Var
   nHour, nMin, nSec, nMSec: Word;
begin
    TimeDecode(fslider.Position,nHour,nMin,nSec,nMsec);
      front_Hour := nHour;
      front_min  := nMin;
      front_sec  := nsec;
      front_msec := nmsec;
end;
procedure TCSTTimeDraw.DrawTimeBack;
Var
   nHour, nMin, nSec, nMSec: Word;
begin
   Timedecode (fSlider.MaxValue - fSlider.Position,nHour,nMin,nSec,nMsec);
      back_Hour := nHour;
      back_min  := nMin;
      back_sec  := nsec;
      back_msec := nmsec;
end;
procedure TCSTTimeDraw.DrawTime (back : Boolean);
begin
  If back = false then begin
   fmsec.Value := front_msec;
   fsec.Value := front_sec;
   fmin.Value := front_min;
   fhour.Value := front_hour;
 end
 else
  If back = true then begin
    fmsec.Value := back_msec;
    fsec.Value := back_sec;
    fmin.Value := back_min;
    fhour.Value := back_hour;
  end;
end;
procedure TCSTTimeDraw.Execute;
begin
  DrawTimeFront;
  DrawTimeBack;
 end;
end.
----------------------------------------------------------
In the Application self

procedure TForm_Raum_1.pos_timer_1Timer(Sender: TObject);
begin
  if not Seeking_1  then pos_slider_1.Position := player1.Position;
    TimeDraw_1.Execute;
    SetRichtung(TimeDraw1,Image1);
end;

procedure SetRichtung (TimeDraw:TCSTTimeDraw;Image:TLabel);
begin
 If Image.Caption = 'Remained' then
TimeDraw.DrawTime(false)
else
If Image.Caption  = 'Elapsed' then
TimeDraw.DrawTime(true);
end;


Greets Chris

DanaPaul

Quotethat does not seem to help. infact it adds (in alot of cases) a minute to the rmin value which is no good.

Hmmm, obvious oversight :) try this...

rmin := 60 - trunc(curtime / 60);
rsec := 60 - trunc((rtime mod 60) + 0.5);

Delete variable "rtime"


breakpoint

@Creadig

Thx for the code but I would not know how to convert it to use with delphi.


@Chris
Thx to you as well but it seems that your component requires additional components for it to work properly. I tried to rip out only the parts that I might need and was unsuccessful in getting it to work but thanks again anyway.


@DanaPaul
Am kinda confused about your last post
Quotermin := 60 - trunc(curtime / 60);
rsec := 60 - trunc((rtime mod 60) + 0.5);

Delete variable "rtime"

you say to delete the rtime variable but in your example you are still using it in the rsec expression. Not exactly sure what you mean.

I tried to run the code as it was and it gave me compiling errors so I modified it abit so it would run and it returned 60:60 for the remaining time and surely that is not right so again I am at a loss.

Again I think I should point out that sometimes the time shows up correctly and at other times it's 1 second behind where it should be so whatever the problem is I can tell you it's sparatic. (sure that narrows it down eh)

Chris

#7
Here the code for an label


unit CSTTimeDraw;

interface

uses
 Windows, Messages, SysUtils, Classes;

type
 TCSTTimeDraw = class(TComponent)
 private
 fSlider : TSlider;
 s_front : string;
 s_back : string;
 fLabel : TLabel

 /// front LEDS;

 procedure DrawTimeFront;
  procedure DrawTimeBack;
 function TimeToString(Time: Longint): string;


   { Private-Deklarationen }
 protected
   { Protected-Deklarationen }
 public
   { Public-Deklarationen }

  procedure DrawTime (back : Boolean);
  procedure Execute;

 published
 property Slider : TSlider read fslider write    fslider;
 property Label: TLabel read fLabel write FLabel;



   { Published-Deklarationen }
 end;

procedure Register;

implementation

procedure Register;
begin
 RegisterComponents('CST-Tools', [TCSTTimeDraw]);
end;

function TimeToString(Time: Longint): string;
begin
   if Time >= 3600000 then
      Result := Format('%d:%2.2d:%2.2d.%3.3d',[Time div 3600000,
                                              (Time mod 3600000) div 60000,
                                              (Time mod 60000) div 1000,
                                               Time mod 1000])
   else
      Result := Format('%d:%2.2d.%3.3d',[Time div 60000,
                                        (Time mod 60000) div 1000,
                                         Time mod 1000]);
end;  
end;

procedure TCSTTimeDraw.DrawTimeFront;
begin
   TimetoString(fslider.position,s_front);
end;
procedure TCSTTimeDraw.DrawTimeBack;
begin
timetostring((fslider.maxvalue- fslider.position),s_back);
end;
procedure TCSTTimeDraw.DrawTime (back : Boolean);
begin
 If back = false then
  fLabel.caption := s_front;
else
 If back = true then
  fLabel.caption := s_back
end;
procedure TCSTTimeDraw.Execute;
begin
 DrawTimeFront;
 DrawTimeBack;
end;
end.


Greets Chris

Ian @ un4seen

It's no great mystery :)

For example...
  total time = 1:31.1 ... 1:31 (truncated)
- elapsed    = 0:10.7 ... 0:10 (truncated)
= remaining  = 1:20.4 ... 1:20 (truncated)
If you're not interest in fractions of a second, the answer is to truncate the numbers (or at least the elapsed time) before doing the subtraction...
curtime := trunc(Bass_ChannelBytes2Seconds(song, Bass_ChannelGetPosition(song)));

breakpoint

thx for the code chris I am sure I will find a use for it and thx to ian as well I should have figured it would have been something simple like that.