Lyrics flow (Delphi / pseudo-code) [closed]
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this questionI would like to build a program which lets lyrics of a song run over the screen. Something like this:
http://www.youtube.com/watch?v=kIAiBvD9njM
Can yo开发者_JAVA技巧u help me?
Algorithm:
- pushes the marker to the right of a line fitting the music
- lets a line above the current line disappear
- inserts a new line above the current line
What is needed?
- lyrics of the song (line per line)
- time to text data? (when does a line start/end)
Some approaches would help me a lot. Pseudo-code or even Delphi code of any part would be fantastic.
If you're interested in karaoke code in pascal, make sure to take a look at UltraStar Deluxe.
It's a super slick and very popular karaoke application. The project is active and it's open source. It can be compiled to various platforms with FPC. You can compile it from both Delphi and Lazarus.. nice.
http://ultrastardx.sourceforge.net/
My neighbours thought that my dog was their worst nightmare until I found this program.
See it in action: po-po-po-pokerface po-po-pokerface.. mum mum mum mah! :)
let's assume you have a text file with the text to be shown and the annotated time of when to hightlight it (kind of a subtitles file, for example the standard proposal w3c timed text (http://www.w3.org/AudioVideo/TT/) or the SUB - Movie subtitle file format in use by several media players.
Your program must first read and parse the text file, and decode the annotated time. Insert it in a stringlist called Subtitles which items would also keep objects similar to this one
type tSubtitle = class
num : integer;
prevTime, fromTime : tdatetime;
toTime, nextTime: tdatetime;
text: string;
end;
You might want to extend the object to hold some highlighting attributes as well.
Then you just need to display those objects synchronized with a timer.
procedure TForm1.Timer1Timer(Sender: TObject);
var rt : TDateTime;
done:boolean;
si,st,sb:integer;
s:string;
begin
rt:=now-startTime;
st:=0;
sb:=subtitles.Count; // binary search the subtitle for the current time
repeat
si:=(st+sb) div 2;
s:=TSubtitle(subtitles.Objects[si-1]);
done:= ((t>=s.prevTime) and (t<=s.nextTime));
if not done then
begin
if t>s.prevTime then st:=si
else if t<s.nextTime then sb:=si;
if st=sb then done:=true;
end;
until done;
// do what you want with s
end;
Another option would be to create your own markup that you parse for that contains both the text and the delay timing. While a timer would work, the problem is that its not going to be accurate enough over time to give you reliable results since its fired based on messaging. Instead, I would perform triggers based on how far from the beginning of the music file you want the event to occur. This also allows the system to catch-up if some other app blocking process gets in the way and should help keep things in sync.
Something as simple as:
00:00:15;LYRIC;This is lyric line 1
00:00:18;FADEOUT
you then can parse this into list of appropriate objects which take the appropriate actions.
You should create a new class based on TGraphicControl/TCustomControl(anything with a canvas) and add a string property, now you have to create a timer as a private variable with it's interval value published through your class, something like so ...
type TLyricViewer = class(TGraphicControl)
private
FTimer : TTimer;
FLyric : string;
FBitmap : TBitmap;// offset bitmap on which you draw
// some more variables to store paint information
private
procedure OnNextWord(Sender: TObject);// assign this to FTimer.OnTimer event
public
constructor Create(AOwner: TComponent);
destructor Destroy; override;
public
procedure StartLyric;
procedure StopLyric;
procedure Paint; override;
published
property WordInterval : Integer|Cardinal
read GetWordInterval write SetWordInterval;
end;
...
procedure TLyricViewer.Paint;
begin
// here is where the magic happends
end;
constructor TLyricViewer.Create(AOwner: TComponent);
begin
// create timer, bitmap and set default properties
end;
destructor TLyricViewer.Destroy;
begin
// free and nil the timer and bitmap
inherited Destroy;
end;
The rest is up to you, after all your the one getting paid, work for it :)
精彩评论