Usdx: Syllable spacing

Created on 28 Dec 2018  路  6Comments  路  Source: UltraStar-Deluxe/USDX

Actual behaviour

Syllables are not spaced correctly (see comparison screenshot below).

Expected behaviour

Syllables should be spaced as if the text was not split up in syllables (see comparison screenshot below).

bildschirmfoto 2018-12-30 um 17 22 16
Explanations for the screenshot:
P1 line shows the individual syllables, split by the vertical bar '|' for visibility
P2 line 1 shows the lyric line _with_ the individual syllables
P2 line 2 shows the lyric line _without_ individual syllables (for comparison)

There are a couple of things to notice:

  • centering the lyrics line does not seem to be correct for P2 line 1 (the relevant case) in comparison to line 2 (correct centering)
  • intra-word syllable spacing is not correct (compare the space between the 'p' and the 's' in 'ipsum' or between 'n' and 's' in 'consectetur' for example - spacing for split up lyrics are smaller than normal)
  • inter-word spacing also seems to be smaller than normal (compare e.g. the space between 'Lorem' and 'ipsum' in the upper and lower P2 line).

I know this is only a cosmetic detail, but I have always noticed and it bugged me. If someone can point me in the direction as to where this is programmed in the source code, I might be able to fix this myself.

This is the text file I used:
P1
: 0 5 0 Lo|rem ip|sum do|lor sit a|met, con|sec|te|tur a|di|pi|si|ci e|lit
P2
: 0 5 0 Lo
: 10 5 0 rem
: 20 5 0 ip
: 30 5 0 sum
: 40 5 0 do
: 50 5 0 lor
: 60 5 0 sit
: 70 5 0 a
: 80 5 0 met,
: 90 5 0 con
: 100 5 0 sec
: 110 5 0 te
: 120 5 0 tur
: 130 5 0 a
: 140 5 0 di
: 150 5 0 pi
: 160 5 0 si
: 170 5 0 ci
: 180 5 0 e
: 190 5 0 lit
- 200
: 200 5 0 Lorem ipsum dolor sit amet, consectetur adipisici elit
E

Details

Provide some additional information:

  • USDX version: branch: bohning-font-refactoring (screenshots taken with Google Noto font)
  • Operating System + version: macOS Mojave 10.14.1
enhancement help wanted

All 6 comments

I played around a little and have found a first quick & dirty solution. In ULyrics, I changed
PosX := PosX + CurWord.Width
to
PosX := PosX + CurWord.Width + 1.45;
in procedure TLyricEngine.DrawLyricsWords() as well as in procedure TLyricEngine.UpdateLineMetrics()

Obviously this is not a good solution, and even with this constant offset, the syllable spacing is improved, but not fully perfect:
bildschirmfoto 2018-12-30 um 17 15 36

How about this approach?:

diff --git a/src/base/ULyrics.pas b/src/base/ULyrics.pas
index 2ac7d2a..2f74565 100644
--- a/src/base/ULyrics.pas
+++ b/src/base/ULyrics.pas
@@ -427,16 +427,15 @@ var
   PosX: real;
   CurWord: PLyricWord;
 begin
-  PosX := X;
+  PosX := X - LyricLine.Words[StartWord].X;

   // set word positions and line size and draw the line
   for I := StartWord to EndWord do
   begin
     CurWord := @LyricLine.Words[I];
     SetFontItalic(CurWord.Freestyle);
-    SetFontPos(PosX, Y);
+    SetFontPos(PosX + CurWord.X, Y);
     glPrint(CurWord.Text);
-    PosX := PosX + CurWord.Width;
   end;
 end;

@@ -444,10 +443,12 @@ procedure TLyricEngine.UpdateLineMetrics(LyricLine: TLyricLine);
 var
   I: integer;
   PosX: real;
+  TextSoFar: UTF8String;
   CurWord: PLyricWord;
   RequestWidth, RequestHeight: real;
 begin
   PosX := 0;
+  TextSoFar := '';

   // setup font
   SetFontStyle(FontStyle);
@@ -492,20 +493,20 @@ begin

     // - if current word is italic but not the next word get the width of the
     // italic font to avoid overlapping.
-    // - if two italic words follow each other use the normal style's
-    // width otherwise the spacing between the words will be too big.
-    // - if it is the line's last word use normal width
-    if CurWord.Freestyle and
-       (I+1 < Length(LyricLine.Words)) and
-       (not LyricLine.Words[I+1].Freestyle) then
-    begin
+    if CurWord.Freestyle then
       SetFontItalic(true);
-    end;

-    CurWord.X := PosX;
     CurWord.Width := glTextWidth(CurWord.Text);
-    PosX := PosX + CurWord.Width;
+    TextSoFar := TextSoFar + CurWord.Text;
+    CurWord.X := PosX + glTextWidth(TextSoFar) - CurWord.Width;
     SetFontItalic(false);
+
+    if (I+1 < Length(LyricLine.Words)) and
+       (CurWord.Freestyle <> LyricLine.Words[I+1].Freestyle) then
+    begin
+      PosX := CurWord.X + CurWord.Width;
+      TextSoFar := '';
+    end;
   end;
 end;

It looks a bit strange though if you use an outline font (Options->Lyrics->Font = OLine2), because TFTOutlineFont.Render will draw the outline over the previous syllable. Ideally we would first draw all outlines and then draw the inner part.

@s09bQ5 Thanks for taking on this issue and for your improved solution that seems plausible to me.

@s09bQ5 please create a pullrequest for your suggested solution, so it is easier for others to test, comment and change your suggested change. Anyways, this code looks good to me - but definitely should be tested with different fonts, styles and different charsets / combined symbols, empty text lines and so on.

@bohning I am still wondering where that magic number 1.45 originates from

@basisbit The magic number came out of trial and error in a few attempts to come close to the expected spacing ;-)

@s09bQ5 Yes, this issue is indeed solved, I just checked. Thanks a lot!
Bildschirmfoto 2019-03-21 um 11 49 22

Was this page helpful?
0 / 5 - 0 ratings