1
0
mirror of synced 2024-11-28 09:20:53 +01:00

Basic WebVTT Support + Sample VTTs on existing OpenTaiko Originals (#458)

* Basic WebVTT support for song lyrics

* Sample VTTs for existing OpenTaiko Originals

- DON'T LOOK BACK
- Dear Stars
- Forever Fading Away
- TRIPLE HELIX
This commit is contained in:
DragonRatTiger 2023-03-25 18:25:55 -04:00 committed by GitHub
parent 7b4f265d6f
commit e6a5968021
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 576 additions and 2 deletions

View File

@ -1309,6 +1309,8 @@ namespace TJAPlayer3
public List<Bitmap> listLyric; //歌詞を格納していくリスト。スペル忘れた(ぉい
public List<STLYRIC> listLyric2;
public bool usingLyricsFile; //If lyric file is used (VTT/LRC), ignore #LYRIC tags & do not parse other lyric file tags
private int listBalloon_Normal_数値管理;
private int listBalloon_Expert_数値管理;
private int listBalloon_Master_数値管理;
@ -1379,6 +1381,7 @@ namespace TJAPlayer3
this.MAKER = "";
this.SELECTBG = "";
this.bLyrics = false;
this.usingLyricsFile = false;
this.eジャンル = Eジャンル.None;
this.PREVIEW = "";
this.PREIMAGE = "";
@ -4001,7 +4004,7 @@ namespace TJAPlayer3
this.listChip.Add(chip);
}
else if (command == "#LYRIC")
else if (command == "#LYRIC" && !usingLyricsFile) // Do not parse LYRIC tags if a lyric file is already loaded
{
if (TJAPlayer3.r現在のステージ.eステージID == CStage.Eステージ.)//起動時に重たくなってしまう問題の修正用
this.listLyric.Add(this.pf歌詞フォント.DrawPrivateFont(argument, TJAPlayer3.Skin.Game_Lyric_ForeColor, TJAPlayer3.Skin.Game_Lyric_BackColor));
@ -5419,7 +5422,48 @@ namespace TJAPlayer3
this.bHIDDENBRANCH = true;
}
}
else if (strCommandName.Equals("LYRICFILE"))
else if (strCommandName.Equals("LYRICS") && !usingLyricsFile)
{
if (!string.IsNullOrEmpty(strCommandParam))
{
string[] files = SplitComma(strCommandParam);
string[] filePaths = new string[files.Length];
for (int i = 0; i < files.Length; i++)
{
filePaths[i] = this.strフォルダ名 + files[i];
if (File.Exists(filePaths[i]))
{
try
{
if (TJAPlayer3.r現在のステージ.eステージID == CStage.Eステージ.)
{
if (filePaths[i].EndsWith(".vtt"))
{
using (VTTParser parser = new VTTParser())
{
this.listLyric2.AddRange(parser.ParseVTTFile(filePaths[i], i, this.pf歌詞フォント));
}
this.bLyrics = true;
this.usingLyricsFile = true;
}
else if (filePaths[i].EndsWith(".lrc"))
{
this.LyricFileParser(filePaths[i], i);
this.bLyrics = true;
this.usingLyricsFile = true;
}
}
}
catch (Exception e)
{
Debug.WriteLine("Something went wrong while parsing a lyric file. More details : {0}", e);
}
}
}
}
}
else if (strCommandName.Equals("LYRICFILE") && !usingLyricsFile)
{
if (!string.IsNullOrEmpty(strCommandParam))
{
@ -5435,6 +5479,7 @@ namespace TJAPlayer3
if (TJAPlayer3.r現在のステージ.eステージID == CStage.Eステージ.)//起動時に重たくなってしまう問題の修正用
this.LyricFileParser(strFilePath[index], index);
this.bLyrics = true;
this.usingLyricsFile = true;
}
catch
{

View File

@ -0,0 +1,235 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static TJAPlayer3.CDTX;
namespace TJAPlayer3
{
public class VTTParser : IDisposable
{
/*
TO-DO :
- Tag support (lang, timestamp, color(?), ruby/rt)
- Adjust bitmap position/anchor when lyric contains newlines (currently snapped to top-center, gets trimmed going down) (also how on earth do i do this lmao)
- NOTE support (for comments within file)
*/
private static string[] _vttdelimiter;
private static Regex regexTimestamp;
private static Regex regexTag;
private static Regex regexOffset;
private static Regex regexLang;
private bool _isDisposed;
public VTTParser()
{
_vttdelimiter = new[] { "-->", "- >", "->" };
regexTimestamp = new Regex(@"(-)?(([0-9]+):)?([0-9]+):([0-9]+)[,\\.]([0-9]+)");
regexTag = new Regex(@"<[^>]*>"); // For now, all tags will be ignored & removed.
regexOffset = new Regex(@"Offset:\s*((-)?(([0-9]+):)?([0-9]+):([0-9]+)[,\\.]([0-9]+));?"); // i.e. "WebVTT Offset: 00:01.001;"
regexLang = new Regex(@"Language:\s*([A-Za-z]+);?"); // i.e. "WebVTT Language: ja;"
}
#region Dispose stuff
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed && disposing)
{
_vttdelimiter = null;
regexTimestamp = null;
regexTag = null;
regexOffset = null;
regexLang = null;
_isDisposed = true;
}
}
#endregion
internal List<STLYRIC> ParseVTTFile(string filepath, int order, CPrivateFastFont drawer)
{
List<STLYRIC> lrclist = new List<STLYRIC>() { };
List<string> lines = File.ReadAllLines(filepath).ToList();
long offset = 0;
// Header stuff
if (lines[0].StartsWith("WEBVTT"))
{
Match languageMatch = regexLang.Match(lines[0]);
if (languageMatch.Success)
{
if (!(languageMatch.Groups[1].Value.ToLower() == CLangManager.fetchLang()))
{
Debug.WriteLine("WebVTT header language does not match user's selected language. Aborting VTT parse.");
return lrclist;
}
}
Match offsetMatch = regexOffset.Match(lines[0]);
if (offsetMatch.Success)
{
offset = ParseTimestamp(offsetMatch.Groups[1].Value);
}
}
else
{
Debug.WriteLine("WebVTT lyric file at {0} does not start with \"WEBVTT\". Aborting VTT parse.");
return lrclist;
}
List<(string, long)> lyrics = new List<(string, long)>() { };
long startTime = -1;
long endTime = -1;
string line = String.Empty;
for (int i = 1; i < lines.Count; i++) // Skip header line (line 0)
{
long start;
long end;
if (TryParseTimestamp(lines[i], out start, out end))
{
if (start > endTime && endTime != -1)
{
lyrics.Add((string.Empty, endTime + offset));
// If new start timestamp is greater than old end timestamp,
// it is assumed there is a gap in-between displaying lyrics.
}
if (startTime != -1)
{
lyrics.Add((line, startTime + offset));
// When new timestamp is found,
// create lyrics with existing timestamp.
}
startTime = start;
endTime = end;
line = string.Empty;
}
else // If timestamp parse failed, let's assume it's a lyric. ¯\_(ツ)_/¯
{
if (line != "") line += Environment.NewLine;
line += String.Join(String.Empty, regexTag.Split(lines[i])); // Remove tags by splitting, then join back into single string
}
}
lyrics.Add((line, startTime + offset));
lyrics.Add((String.Empty, endTime + offset));
foreach ((string, long) lyric in lyrics)
{
lrclist.Add(CreateLyric(lyric, drawer, order));
}
return lrclist;
}
internal bool TryParseTimestamp(string input, out long startTime, out long endTime)
{
var split = input.Split(_vttdelimiter, StringSplitOptions.None);
if (split.Length == 2 && regexTimestamp.IsMatch(split[0]) && regexTimestamp.IsMatch(split[1]))
{
startTime = ParseTimestamp(split[0]);
endTime = ParseTimestamp(split[1]);
return true;
}
else
{
startTime = -1;
endTime = -1;
return false;
}
}
internal long ParseTimestamp(string input)
{
int hours;
int minutes;
int seconds;
int milliseconds = -1;
Match match = regexTimestamp.Match(input);
if (match.Success)
{
hours = !string.IsNullOrEmpty(match.Groups[3].Value) ? int.Parse(match.Groups[3].Value) : 0; // Hours are sometimes not included in timestamps.
minutes = int.Parse(match.Groups[4].Value);
seconds = int.Parse(match.Groups[5].Value);
milliseconds = int.Parse(match.Groups[6].Value);
TimeSpan result = new TimeSpan(0, hours, minutes, seconds, milliseconds);
return (long)result.TotalMilliseconds * (match.Groups[1].Value == "-" ? -1 : 1);
}
return -1;
}
internal STLYRIC CreateLyric(string lyric, long time, CPrivateFastFont draw, int order)
{
return CreateLyric((lyric, time), draw, order);
}
internal STLYRIC CreateLyric((string, long) lyric, CPrivateFastFont draw, int order)
{
string[] split = lyric.Item1.Split(new string[]{"\\r\\n", "\\n", "\r\n", "\n"}, StringSplitOptions.RemoveEmptyEntries);
List<Bitmap> textures = new List<Bitmap>();
int width = 1;
int height = 1;
for (int i = 0; i < split.Length; i++)
{
textures.Add(draw.DrawPrivateFont(split[i], TJAPlayer3.Skin.Game_Lyric_ForeColor, TJAPlayer3.Skin.Game_Lyric_BackColor));
width = width < textures[i].Width ? textures[i].Width : width;
height += textures[i].Height;
}
Bitmap texture = new Bitmap(width, height);
if (textures.Count != 0)
{
using (Graphics canvas = Graphics.FromImage(texture))
{
canvas.Clear(Color.Transparent);
Point pos = new Point(0, 0);
foreach (Bitmap bitmap in textures)
{
pos.X = (width - bitmap.Width) / 2;
canvas.DrawImage(bitmap, pos);
pos.Y += bitmap.Height;
}
}
}
STLYRIC stlrc = new STLYRIC()
{
Text = lyric.Item1,
TextTex = texture,
Time = lyric.Item2,
index = order
};
return stlrc;
}
}
}

View File

@ -152,6 +152,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Songs\C曲リストードComparers\C曲リストードComparerLevel.cs" />
<Compile Include="Songs\C曲リストードComparers\C曲リストードComparerSubtitle.cs" />
<Compile Include="Songs\VTTParser.cs" />
<Compile Include="Stages\01.StartUp\CCharacter.cs" />
<Compile Include="Stages\01.StartUp\CPuchichara.cs" />
<Compile Include="Stages\07.Game\Taiko\AIBattle.cs" />

View File

@ -4,6 +4,7 @@ BPM:200
WAVE:DON'T LOOK BACK.ogg
OFFSET:-0.0095
DEMOSTART:44.082
LYRICS:DON'T LOOK BACK.vtt
SCOREMODE:2
PREIMAGE:DLB.png
MAKER:bol

View File

@ -0,0 +1,43 @@
WEBVTT
01:18.205 --> 01:20.338
Coming through straight, I rest my case (Do it, do it)
01:20.338 --> 01:22.472
Hands up in the sunshine when we (Do it, do it)
01:22.472 --> 01:24.338
You know that when the beat drop, I always need more
01:24.338 --> 01:25.672
But that shawty says she with the glock so
01:25.672 --> 01:25.938
DON'T
01:25.938 --> 01:26.205
DON'T LOOK
01:26.205 --> 01:26.738
DON'T LOOK BACK
01:26.738 --> 01:28.872
Coming through straight, I rest my case (Do it, do it)
01:28.872 --> 01:31.005
Hands up in the sunshine when we (Do it, do it)
01:31.005 --> 01:32.872
You know that when the beat drop, I always need more
01:32.872 --> 01:34.205
But that shawty says she with the glock so
01:34.205 --> 01:34.472
DON'T
01:34.472 --> 01:34.738
DON'T LOOK
01:34.738 --> 01:35.005
DON'T LOOK BACK

View File

@ -5,6 +5,7 @@ WAVE:stars.ogg
OFFSET:-0.028
MAKER:Dashy
DEMOSTART:59.472
LYRICS:stars.vtt
PREIMAGE:stars.png
BGMOVIE:stars.mp4

View File

@ -0,0 +1,90 @@
WEBVTT
00:00.732 --> 00:07.683
another day has passed
00:07.683 --> 00:13.902
and you've awakened as always
00:13.902 --> 00:20.488
each and every million of stars, you're all
00:20.488 --> 00:25.427
finally with me at last
00:25.427 --> 00:33.659
so i ask to you, dear stars...
00:36.585 --> 00:39.146
"why must this happen?
00:39.146 --> 00:42.439
these little mistakes hurt so much
00:42.439 --> 00:45.183
all of these fake words
00:45.183 --> 00:48.110
all i did today... hurt so much"
00:48.110 --> 00:51.036
"i can only hide these feelings each day
00:51.036 --> 00:53.780
and stay tainted with regret
00:53.780 --> 00:56.890
and perhaps you're the only ones
00:56.890 --> 01:00.000
who understand how i feel"
01:00.000 --> 01:05.487
"shining above me, watching over me
01:05.487 --> 01:08.597
i can only wish, dear stars
01:08.597 --> 01:11.524
that you could tell me what i could do"
01:11.524 --> 01:14.634
"you saw everything, you felt everything,
01:14.634 --> 01:17.378
you've been through it all, you know it all"
01:17.378 --> 01:18.841
why can't i just stay here
01:18.841 --> 01:20.304
and find you all again
01:20.304 --> 01:22.682
until i fall asleep?
01:22.682 --> 01:25.609
dear twinkling, shining stars,
01:25.609 --> 01:29.268
oh, whatever could i do...?
01:52.682 --> 01:58.170
i don't want to go on
i don't want to, i don't want to, i don't want to, i don't want to,
01:58.170 --> 02:03.292
i can't keep going anymore
not anymore, not anymore, not anymore...
02:03.292 --> 02:06.036
so, dear stars,
so, dear stars,
02:06.036 --> 02:13.170
let me stay with you forever
let me stay with you forever
02:13.170 --> 02:16.096
please
please

View File

@ -4,6 +4,7 @@ BPM:200
WAVE:Forever Fading Away.ogg
OFFSET:-0.029
DEMOSTART:95.529
LYRICS:Forever Fading Away.vtt
PREIMAGE:Forever Fading Away.png
BGMOVIE:Forever Fading Away.mp4
MAKER:DashyDesu & Colin

View File

@ -0,0 +1,142 @@
WEBVTT
00:38.400 --> 00:44.100
Cloudless faded light blue skies
00:44.100 --> 00:48.000
surrounded the world he saw
00:48.000 --> 00:52.800
an urgency was suddenly born
00:52.800 --> 00:57.600
as that memory began to disappear...
00:57.600 --> 01:01.800
place, faces, sounds and tastes
01:01.800 --> 01:06.900
empty streets, and light gray drizzling clouds
01:06.900 --> 01:11.400
He seeked to discover the reason
01:11.400 --> 01:16.800
for such settings being so familiar
01:16.800 --> 01:17.400
mem
01:17.400 --> 01:18.000
memor
01:18.000 --> 01:18.600
memories
01:18.600 --> 01:19.200
memories and
01:19.200 --> 01:19.800
memories and frag
01:19.800 --> 01:20.400
memories and fragments
01:20.400 --> 01:21.000
memories and fragments of
01:21.000 --> 01:21.600
memories and fragments of that
01:21.600 --> 01:22.800
memories and fragments of that time
01:22.800 --> 01:23.400
he
01:23.400 --> 01:24.000
he re
01:24.000 --> 01:25.200
he remem
01:25.200 --> 01:26.400
he remembered
01:26.400 --> 01:27.000
that
01:27.000 --> 01:27.600
that mom
01:27.600 --> 01:28.200
that moment
01:28.200 --> 01:28.800
that moment breezed
01:28.800 --> 01:29.400
that moment breezed by
01:29.400 --> 01:30.000
that moment breezed by from
01:30.000 --> 01:30.600
that moment breezed by from long
01:30.600 --> 01:31.200
that moment breezed by from long a
01:31.200 --> 01:32.400
that moment breezed by from long ago
01:32.400 --> 01:33.000
he
01:33.000 --> 01:33.600
he re
01:33.600 --> 01:34.200
he real
01:34.200 --> 01:35.400
he realized...
01:35.400 --> 01:37.800
as all those moments dissolve away,
01:37.800 --> 01:40.200
just like always...
01:40.200 --> 01:45.000
just like always, he'll continue living life his way...
01:45.000 --> 01:51.600
only covered in thoughts as time fades away
01:51.600 --> 01:54.750
time and time again...
01:54.750 --> 01:59.400
no matter hours, seconds, weeks, they disappear
01:59.400 --> 02:04.200
they disappear and are left with not any meaning
02:04.200 --> 02:10.800
the time passes and then never reappears...
02:10.800 --> 02:19.200
he stays in that pure white world...
02:33.600 --> 02:43.200
now this time that was once at his fingertips
02:43.200 --> 02:49.200
had began to drift away
02:49.200 --> 02:52.800
so he remains in the pure white world...
02:52.800 --> 03:02.400
forever, endless, ilimitable.

View File

@ -4,6 +4,7 @@ BPM:160
WAVE:TRIPLE HELIX.ogg
OFFSET:-0.001
DEMOSTART:120.001
LYRICS:TRIPLE HELIX.vtt
MAKER:Colin
COURSE:Oni

View File

@ -0,0 +1,14 @@
WEBVTT
00:42.000 --> 00:57.000
(rapping)
01:00.000 --> 01:03.375
(rapping)
01:06.000 --> 01:09.000
(rapping)
01:11.813 --> 01:15.000
(rapping)