doctorjellybean
Programmer
- May 5, 2003
- 145
It all started on this post, and I'm very grateful to Daddy and Glenn for their input on that.
I had to make some changes, because the original code in that post created and read the timestamps in the [000000] format, and I discovered later that it needed to be done in the [00:00.00] format.
The amended code works, but I've discovered that it is perfectly in sync for the first minute. After that the lyrics seems to appear a millisecond/second before it's due. It doesn't make sense to me, as it uses the same code to create and read back.
The following is the Time creation code
The code in the Media Player for playback
I've uploaded the project and an example (2MB), as it might be easier to try it than just reading the code.
Just as a matter of interest. I've also tried this amended code in D6, because D6 doesn't recognize MSecsPerSec.
The example project was created in D2010, and wether I use dt := vPos / MSecsPerSec / SecsPerDay; or Dt := vPos / (24*60*60*1000) / (24*60*60); doesn't appear to make any difference.
I hope someone can figure out this very strange behaviour.
Thanks in advance.
I had to make some changes, because the original code in that post created and read the timestamps in the [000000] format, and I discovered later that it needed to be done in the [00:00.00] format.
The amended code works, but I've discovered that it is perfectly in sync for the first minute. After that the lyrics seems to appear a millisecond/second before it's due. It doesn't make sense to me, as it uses the same code to create and read back.
The following is the Time creation code
Code:
function TExistingLyricsForm.PostionToTime(const vPos : Integer) : String;
var
dt : TDateTime;
begin
Result := '00:00.00';
if vPos <= 0 then Exit;
dt := vPos / MSecsPerSec / SecsPerDay;
// milliseconds can be displayed with leading zeros
// and without leading zeros but can have 3 digits
// so default it to milliseconds with leading zeros
// and get rid of the last digit
Result := Copy(FormatDateTime('nn:ss.zzz', dt), 1, 8);
end;
function MinutesToMilli(vMinutes : String) : Integer;
var
iPos, iMinutes, iSeconds : Integer;
sTmp : String;
begin
try
sTmp := vMinutes;
iPos := Pos(':', sTmp);
iMinutes := (StrToInt(Copy(sTmp, 1, iPos - 1)) * 60000);
sTmp := Copy(sTmp, iPos+1, Length(sTmp));
iPos := Pos('.', sTmp);
iSeconds := (StrToInt(Copy(sTmp, 1, iPos - 1)) * 100);
if iMinutes > 0 then
iSeconds := iSeconds * 10;
sTmp := Copy(sTmp, iPos+1, Length(sTmp));
Result := (iMinutes + iSeconds + StrToInt(sTmp));
if Result < 60000 then
Result := (Result * 10);
except
Result := 0;
end;
end;
procedure LoadLyricFile(LFile: string);
var
LTextfile: Text;
LTextString: String;
RPos: integer;
begin
assign(LTextFile, LFile);
Reset(LTextFile);
LyricCount := 1;
while not eof(LTextFile) do
begin
readln(LTextFile, LTextString);
RPos := Pos(']', LTextString);
LyricRecord[LyricCount].LyricLine :=
Copy(LTextString, RPos+1, Length(LTextString)-RPos);
LyricRecord[LyricCount].OffsetStr :=
Copy(LtextString, 2, RPos-2);
LyricRecord[LyricCount].OffsetStr :=
Copy(LtextString, 2, RPos-2);
LyricRecord[LyricCount].Offset :=
MinutesToMilli(LyricRecord[LyricCount].OffsetStr);
inc(lyriccount);
end;
{ to signal the logic we're done with the data }
LyricRecord[LyricCount].Offset := 999999999;
close(LTextFile);
end;
procedure TExistingLyricsForm.Btn_CreateTimeStampsClick(Sender: TObject);
begin
if Btn_CreateTimeStamps.Caption='Create Blank' then begin
memo_lyrics.lines.Add('['+PostionToTime(MediaPlayer1.Position)+']');
btn_createtimestamps.Caption:='Create Time';
btn_createtimestamps.Enabled:=false;
exit end else
if Btn_ClearTimeStamps.Enabled=false then Btn_ClearTimeStamps.Enabled:=true;
if x = 0 then begin
memo_lyrics.lines.Delete(x);
memo_lyrics.lines.Insert(x,'['+PostionToTime(MediaPlayer1.Position)+']'+lyricslist[x]);
{memo_timestamps.items.Add('['+inttostr(mediaplayer1.Position)+']'+lyricslist[x]);}
x:= x+1;
exit end else
{lyricslist.Count;
if lyricslist.Count=x then begin
Btn_CreateStamps.Enabled:=false;
exit end else}
memo_lyrics.lines.Delete(x);
memo_lyrics.lines.Insert(x,'['+PostionToTime(MediaPlayer1.Position)+']'+lyricslist[x]);
x:=x+1;
if lyricslist.Count=x then Btn_CreateTimeStamps.Caption:='Create Blank';
if lyricslist.Count=x then Btn_TestTimeStamps.Enabled:=true;
if lyricslist.Count=x then Btn_SaveTimeStamps.Enabled:=true;
end;
The code in the Media Player for playback
Code:
function TMediaPlayerForm.PostionToTime(const vPos : Integer) : String;
var
dt : TDateTime;
begin
Result := '00:00.00';
if vPos <= 0 then Exit;
dt := vPos / MSecsPerSec / SecsPerDay;
// milliseconds can be displayed with leading zeros
// and without leading zeros but can have 3 digits
// so default it to milliseconds with leading zeros
// and get rid of the last digit
Result := Copy(FormatDateTime('nn:ss.zzz', dt), 1, 8);
end;
function MinutesToMilli(vMinutes : String) : Integer;
var
iPos, iMinutes, iSeconds : Integer;
sTmp : String;
begin
try
sTmp := vMinutes;
iPos := Pos(':', sTmp);
iMinutes := (StrToInt(Copy(sTmp, 1, iPos - 1)) * 60000);
sTmp := Copy(sTmp, iPos+1, Length(sTmp));
iPos := Pos('.', sTmp);
iSeconds := (StrToInt(Copy(sTmp, 1, iPos - 1)) * 100);
if iMinutes > 0 then
iSeconds := iSeconds * 10;
sTmp := Copy(sTmp, iPos+1, Length(sTmp));
Result := (iMinutes + iSeconds + StrToInt(sTmp));
if Result < 60000 then
Result := (Result * 10);
except
Result := 0;
end;
end;
procedure LoadLyricFile(LFile: string);
var
LTextfile: Text;
LTextString: String;
RPos: integer;
begin
assign(LTextFile, LFile);
Reset(LTextFile);
LyricCount := 1;
while not eof(LTextFile) do
begin
readln(LTextFile, LTextString);
RPos := Pos(']', LTextString);
LyricRecord[LyricCount].LyricLine :=
Copy(LTextString, RPos+1, Length(LTextString)-RPos);
LyricRecord[LyricCount].OffsetStr :=
Copy(LtextString, 2, RPos-2);
LyricRecord[LyricCount].OffsetStr :=
Copy(LtextString, 2, RPos-2);
LyricRecord[LyricCount].Offset :=
MinutesToMilli(LyricRecord[LyricCount].OffsetStr);
inc(lyriccount);
end;
{ to signal the logic we're done with the data }
LyricRecord[LyricCount].Offset := 999999999;
close(LTextFile);
end;
procedure TMediaPlayerForm.Timer_TrackPlayerTimer(Sender: TObject);
begin
if MediaPlayer1.Position >= LyricRecord[LyricPos].Offset then
begin
label_lyrics.caption:= LyricRecord[LyricPos].LyricLine;
inc(LyricPos);
end;
if MediaPlayer1.Position = MediaPlayer1.TrackLength[1] then
begin
Timer_TrackPlayer.Enabled := false;
LyricPos := 1;
end;
end;
I've uploaded the project and an example (2MB), as it might be easier to try it than just reading the code.
Just as a matter of interest. I've also tried this amended code in D6, because D6 doesn't recognize MSecsPerSec.
Code:
function TLyricsMediaPlayerForm.PostionToTime(const vPos : Integer) : String;
var
dt : TDateTime;
begin
Result := '00:00.00';
if vPos <= 0 then Exit;
Dt := vPos / (24*60*60*1000) / (24*60*60);
// milliseconds can be displayed with leading zeros
// and without leading zeros but can have 3 digits
// so default it to milliseconds with leading zeros
// and get rid of the last digit
Result := Copy(FormatDateTime('nn:ss:zzz', dt), 1, 8);
end;
The example project was created in D2010, and wether I use dt := vPos / MSecsPerSec / SecsPerDay; or Dt := vPos / (24*60*60*1000) / (24*60*60); doesn't appear to make any difference.
I hope someone can figure out this very strange behaviour.
Thanks in advance.