Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

TTimer in Delphi to display synced lyrics? 6

Status
Not open for further replies.

doctorjellybean

Programmer
May 5, 2003
145
There is a clever program called MiniLyrics, and I want to achieve the same effect in my multimedia application.

That is, when it plays a track, it loads the lyrics from a file and display it synchronized to the track. MiniLyrics uses timestamps in its file, e.g.

[00:07.79]Jennifer Juniper lives upon the hill,
[00:15.23]Jennifer Juniper, sitting very still.
[00:23.36]Is she sleeping ? I don't think so.
[00:26.55]Is she breathing ? Yes, very low.


Is it possible to achieve the same object with the TTimer component, and if yes, what is the best way?

Thank you.
 
Not to worry about the changes, I have figured it out [smile].

I just amended the OnLyric procedure

procedure TFrm_main.OnLyric(Sender: TObject);

var Lyric : TLyric;

begin
Lyric := TLyric(Sender);
Memo.Clear;
Memo.Lines.Add(Lyric.Lyric)
end;
 
that is up to you. if you want to display a single line, use a TLabel and set the caption to Lyric.Lyric
or just do memo.Text := Lyric.Lyric;

Code:
procedure TFrm_main.OnLyric(Sender: TObject);

var Lyric : TLyric;

begin
 Lyric := TLyric(Sender);
// do whatever you want with the Lyric....
end;

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
I just tested my amended code, and it doesn't display the first line (seems to clear it before displaying it). It displays the rest ok. I'll try the TLabel option.

Thank you.
 
I've just realized that the original code doesn't display the first line of the lyrics. If you look at the screenshot


You'll see that it starts with

[00:15.23]Jennifer Juniper, sitting very still

and it misses the first line

[00:07.79]Jennifer Juniper lives upon the hill

If I change the timecode for the first line to [00.10.00] it displays immediately, but any number less than 10 it doesn't display.

Any ideas?
 
if you examine my code you'll see that the play method has
an offset (in time) parameter

procedure TLyricsThread.Play(LyricsFile : String; Offset: Integer);

the example calls Play with 10 seconds offset, this means it will only display Lyrics that come after 10 seconds.

the reason I added this, is because a user could start the sound not from the beginning, but somewhere in the middle.

My point is, don't take this code for granted and try to learn from it.

[thumbsup]

Cheers,
Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Thank you!

I have to admit that it has been at least 4 years since I did programming. Guess I'm either rusty or have forgotten the basics [sad]
 
pause functionality could be added

This would be great, and the ability to continue from the pause point. I had a look at the code, and I'm not sure how or where to add this. Threads are not my strong point. Actually, I don't think I have ever used it until now.

I would really appreciate it if you could explain how to do this [thumbsup2]. Thank you.
 
Would I be correct in saying that the lyric thread has to be executed before anything else?

I created a simple media player to play the track. If I start the media player first, the lyric display shows the message "playing stopped". If I execute the lyric thread before playing the media track, then it is fine.
 
If I execute the lyric thread before playing the media track, then it is fine.

question, how do you play the track? does it allow to be interrupted (to enable the Onlyric event)?
Show some code...

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
My apologies. I tried the lyric thread with a freeware 3rd party audio component, which caused the problems. I then did a quick and dirty experiment with TMediaPlayer and it appears to work just fine. Now if I can work out how to pause the lyric thread ...
 
Now if I can work out how to pause the lyric thread ...

LyricsThread.Suspend;

LyricsThread.Resume; to unpause it.

(and I feel your pain that you describe. TThread is rather poor in a lot of respects)
 
TThread is rather poor in a lot of respects

Glenn, can you explain this bit. I tend to use threads, whenever I can (if there is a real advantage). I Don't have any problems with using TThread...

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Glenn, can you explain this bit. I tend to use threads, whenever I can (if there is a real advantage). I Don't have any problems with using TThread...

Uhm, it's been quite a while since I seriously played with TThread, especially since I sought other methods. But from what I know/remember of it (and looking at my old sample to answer the question above), my observations:

1) Trying to get it to work right. Too many i's to dot and t's to cross. Too many "it looks right but does nothing" moments in the two programs I did with it. Ultimately I found it to be too much effort for the return.

2) Requires a separate unit in most implementations to get the general framework down. Not a simple "fire it off" affair. Again, much work, little return.

3) For most implementations I've done where threads could be useful, Application.ProcessMessages; let the functionality be sufficient. Of course, there are problems with A.P which are eliminated with threads, but not so much that I have noticed. Again much work, little return to do thread.

4) Separate unit, and the way it is implemented raises complexity. What if I have five or ten thread routines? Five or ten units? I could copy for #2 and this point, but it doesn't work out very well with how the design is or the expectation.

5) Not very extensible - I'm thinking extensive multi-threading solutions with an eye to multi-processing. I have a multi-threading quicksort done (not sure if I still have the source or where it is) - that was tricky enough to get my mind around. Nevermind trying to do it with TThread.

6) What can you do and can't do within TThread? That's one I've run into almost constantly where code tested and working outside of TThread doesn't work right in TThread for some reason. I don't get that with BeginThread/EndThread.

7) I don't know this one for sure personally, but I've been told TThread is hideously inefficient if you hammer it enough within routines.

From what I read in different forums (Usenet Delphi, Borland's and others), most people tend to push towards using A.P; or BeginThread/EndThread along with some adapted procedures for other tasks, like Suspend/Resume and changing priority - and I've been heavily urged in posts there to do the same (to the point of parts of TThread - primarily Synchronize - being described as "doing next to nothing good").

Actually, I'm pretty interested in what you think - what do you see as the advantages and disadvantages of TThread, Application.ProcessMessages, and BeginThread/EndThread?
 
Glenn

Do you think you could post a complete example, so that I could try it out and compare it with Daddy's code. Daddy's code works quite well, but I guess it won't do any harm to experiment [dazed]. This way I can learn too.

Thanks in advance [smile]

For resolution sake, I don't think any more than millisecond resolution is necessary in this case. As far as timing code goes, I do have something more involved worked out (from help on here in fact) I can post. But the simplest is this:

function WinMSSinceStart: DWord;
stdcall; external 'winmm.dll' name 'timeGetTime';
It turns a number of Milliseconds since the multi-media timer is initialized (I guess?). Calling it is simple:

Result := WinMSSinceStart;
Load all your timestamps and lyrics into an array, converting them to MS values, and then before you start the song, call this. Then in a loop, call the routine and then check each entry as it comes up in your table - if the time elapsed (currenttime-startingtime) is greater or equal to the lyric time, then display the lyric and move on to the next entry.
 
1) Trying to get it to work right. Too many i's to dot and t's to cross. Too many "it looks right but does nothing" moments in the two programs I did with it. Ultimately I found it to be too much effort for the return.

that was just my point! I takes a while to get thing right with threads. There are some basic rules and once you know and understand them, there is really nothing to it!

this guide is really brilliant:

I suggest you read it.

I agree on the fact that TThread has had some issues, but I don't see why I would attack the API (beginthread, terminatethread), if one has issues with TThread, you can always make your own thread class.

Application.Processmessages does not speed up things, it only makes the GUI responsive, while with threads you can do work in parallel. take for instance loading a big resultset from a database in background, and that sort of stuff. In a time where dual (and quad) core processors are more and more common, it is our responsability to make use of that extra processing power...

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 

I know it was intended for Glenn, but this looks very interesting. Thank you [smile].

By the way, I did some shopping over the weekend and got a copy of Delphi 2007. Erm, it looks very different. This time I could use your complete code Daddy, without it throwing up errors like

[Error] u_class_lyrics.pas(75): Undeclared identifier: 'TFormatSettings'
[Error] u_class_lyrics.pas(83): Undeclared identifier: 'GetLocaleFormatSettings'
 
doctorjellybean said:
Do you think you could post a complete example, so that I could try it out and compare it with Daddy's code. Daddy's code works quite well, but I guess it won't do any harm to experiment . This way I can learn too.

I'd love to try it when the time comes available, I just don't have any data files to run against.

whosrdaddy said:
that was just my point! I takes a while to get thing right with threads. There are some basic rules and once you know and understand them, there is really nothing to it!

I was referring to TThread more than threads in general. Though I have seen the reference you refer to, thanks for the reminder of it (so much material to look through so little time!).

whosrdaddy said:
but I don't see why I would attack the API (beginthread, terminatethread),

Not really the API, both are another Delphi implementation of the API...

About 90% of the cases I've seen or read about involve things where A.P; is suitable - usually to get the GUI responsive while some processing is occurring. So it makes it an option to consider. Really though, I've only encountered five cases where threading was an absolute necessity.
 
(Glenn9999);
I'd love to try it when the time comes available, I just don't have any data files to run against.

You could just use the complete lyric near the top, save it as a txt file and take it from there [smile]
 
I've been enjoying this thread (groan!) so have another star on me, whosrdaddy!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top