开发者

Lyrics flow (Delphi / pseudo-code) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.

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 question

I 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 :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜