<div dir="ltr">Hello everyone,<div><br></div><div>I am applying to GSoC 2014 for the idea "Lyric Support Improvements". I am appending my draft proposal. The proposal isn't complete; only the scrolling lyrics part is written while the lyrics fetching is left.</div>
<div>Please review and tell me where something is ambiguous or incorrect.</div><div>I hope you like it, I have done a lot of research this time.</div><div><br></div><div>Sincerely,</div><div>Vedant.</div><div><br></div><div>
-------------Proposal below-------------------</div><div><br></div><div><span id="docs-internal-guid-1217c193-97a8-bf01-60fa-47374089218b"><p dir="ltr" style="line-height:1.4625;margin-top:0pt;margin-bottom:0pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap">Name: </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);vertical-align:baseline;white-space:pre-wrap">Vedant Agarwala</span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap"></span></p>
<p dir="ltr" style="line-height:1.4625;margin-top:0pt;margin-bottom:0pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap">Email Address: </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);vertical-align:baseline;white-space:pre-wrap"><a href="mailto:vedant.kota@gmail.com">vedant.kota@gmail.com</a></span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap"></span></p>
<p dir="ltr" style="line-height:1.4625;margin-top:0pt;margin-bottom:0pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap">IRC Nick: </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);vertical-align:baseline;white-space:pre-wrap">vedu</span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap"></span></p>
<p dir="ltr" style="line-height:1.4625;margin-top:0pt;margin-bottom:0pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap">IM Service and Username: </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);vertical-align:baseline;white-space:pre-wrap">xmpp-google: <a href="mailto:vedant.kota@gmail.com">vedant.kota@gmail.com</a></span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap"></span></p>
<p dir="ltr" style="line-height:1.4625;margin-top:0pt;margin-bottom:0pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap">Location (City, Country and/or Time Zone): </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);vertical-align:baseline;white-space:pre-wrap">Kolkata, India GMT+5.30</span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap"></span></p>
<p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:11pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-weight:bold;vertical-align:baseline;white-space:pre-wrap">Proposal Title:</span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"> </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-weight:bold;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap">Lyric Support Improvements</span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap"></span></p>
<p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap">Motivation for Proposal and Overview: </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);vertical-align:baseline;white-space:pre-wrap">Currently </span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">Amarok supports the fetching and display of lyrics. Fetching is performed by scripts, which by default is Lyicwiki. Display is in a basic Text Browser widget that scrolls at a constant rate so that the start and end times of the song playback and lyrics display coincide. This is rarely the case in actual playback due to many reasons: different lines of the song are played at different rates, in between paragraphs there is one (blank) line but many seconds of music, etc. Also the Text Browser Widget is currently in duress, as the background is white instead of the consistent blue (Bug 314854</span><a href="https://bugs.kde.org/show_bug.cgi?id=314854" style="text-decoration:none"><span style="font-size:13px;font-family:Arial;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap">[1]</span></a><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">).</span></p>
<p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">I want to fix this. I have a two fold goal in my proposal: improve the chances of lyrics fetching and, highlight the “current playing line” according to the timestamp in the .lrc file. For smooth highlighting I want to magnify the current playing line. It will appear as if there is a rectangular magnifying glass along the width of the widget with the current playing line at the centre while the lyrics scrolls underneath it (without the lensing effect that occurs at the edges of a actual magnifying glass). For better fetching I will add more sources from which lyrics can be fetched, and make a more useful action for the “reload lyrics” button i.e. lyrics will be taken from a new source on button click. To improve chances of lyrics being fetched for songs with poor tags, I will add automatic adjustment of tags (without changing the saved tracks) for artist and song name i.e. omitting track numbers, bracket, parenthesis, ‘feat’, etc.</span></p>
<br><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"></span><p dir="ltr" style="line-height:1.4625;margin-top:0pt;margin-bottom:0pt">
<span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap">Implementation Details:</span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"></span></p>
<ul style="margin-top:0pt;margin-bottom:0pt"><li dir="ltr" style="list-style-type:disc;font-size:13px;font-family:Arial;font-style:italic;vertical-align:baseline"><p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt">
<span style="color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">Changing the LyricsBrowser:</span><span style="color:rgb(0,0,0);background-color:transparent;font-style:normal;vertical-align:baseline;white-space:pre-wrap"> All the code for display of lyrics is contained in the directory ‘src/context/applets/lyrics’. The LyricsApplet class (a subclass of the Plasma::Applet) has a object of the LyricsBrowser class set as the “browser”. This serves our purpose quite well because the LyricsBrowser ultimately inherits the QWidget that is a QPaintDevice. This means we can use QPainter on it. I will edit the LyricsBrowser.cpp|h files, add a public slot that will listen to the current position (in milliseconds) of the song playing. As before, the applet will display the current playing song’s lyrics, and the process of displaying (fetching, pasring .lrc file, etc.) will begin as soon as a new track starts playing. Some changes will be needed in the properties of LyricsBrowser: it will be immune to all direct user interactions i.e. its focusPolicy property will be Qt::NoFocus. It will not accept any user clicks, or scrolls. Any editing to this will have to be made from the settings box, like changing the font of the lyrics. Its height will be fixed and width will be according to QSizePolicy::MinimumExpanding; similar to the “Current track” applet.</span></p>
</li></ul><p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt;margin-left:34.5pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">In the LyricsBrowser, I will create a rectangular “lens”; it will progressively zoom in on the line in focus. Lines above and below it will gradually return to their original size. Number of lines will depend on the font size. Say, the entire lens will affect five lines at any given time: the middle one is zoomed in to 1.5x at its centre while the start of the first line and end of last line at 1.0x, progression from 1.0x to 1.5x and back to 1.0x will be linear. The exact figures of number of lines, maximum zoom level and steepness of the gradient of the power of the lens are GUI components and can be decided accurately during actual implementation with some trial and error testing. The magnifying glass itself will be invisible or have a light translucent color in the middle that highlights the current playing line even more. If time permits, I can test certain colors with different Composition Modes of the QPainter (like QPainter::CompositionMode_Lighten) and share snapshots with the Amarok community to collaboratively decide which look would be the best. The code to do this is inspired from the “Vector Deformation” demo</span><a href="http://qt-project.org/doc/qt-5/qtwidgets-painting-deform-example.html" style="text-decoration:none"><span style="font-size:13px;font-family:Arial;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap">[2]</span></a><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">: </span><img src="https://lh4.googleusercontent.com/sxToPMiyj1ZT2p8L89xOndfnQWTZH-Kq6NgKu6LWna9nQ_AiZd6pSlK5WyO--4RRUVfOd4fkQd3BmTDSOp4WVOdFzRS-k3POUAJEEcGApfjcEXSxX-DzYbt7w5jeCw" width="277px;" height="209px;" style="border: none;"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"> I will add a function generateLensPixmap() in the LyricsBrowser class to paint the lens (unless its invisible). I will initialize a QPainter as “QPainter painter(this)” and draw the lens as “painter.drawRect()”. ‘generateLensPixmap()’ will be called during object construction and everytime the font size is changed. Just the way in the Vector Deformation example, the lensDeform() function creates a spherical deformation, I will also create a lensDeform() that will perform a rectangular deformation. As the widget will should be updated continually as the song progresses, I will connect the ‘The::engineController()->trackPositionChanged()’ signal to an appropriate (private) slot in LyricsBrowser class, say ‘trackProgressed()’. This slot will call lensDeform() in a nested loop (for every point in the area of the widget) and then call update(). The current behaviour of showing a busy sign in the widget while a lyrics is being fetched, is just fine. If by chance the saved lyrics is a .txt file or a .lrc file with no timestamps, the lyrics will be displayed as they are now. As you will see in the next point, we will require total of three states of LyricsBrowser: scrolling lyrics, stagnant lyrics, and lyrics edit.</span></p>
<ul style="margin-top:0pt;margin-bottom:0pt"><li dir="ltr" style="list-style-type:disc;font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;font-style:italic;vertical-align:baseline"><p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt">
<span style="background-color:transparent;vertical-align:baseline;white-space:pre-wrap">Change the LyricsApplet: </span><span style="background-color:transparent;font-style:normal;vertical-align:baseline;white-space:pre-wrap">The container for LyricsBrowser i.e. LyricsApplet, will also have to be updated. Clicking the “Edit lyrics” button will take the LyricsBrowser to the ‘lyics edit’ state. The widget will expand (in length) to take up all the available space and become just the old (i.e. current) LyricsBrowser in ‘edit’ state: the lyrics will become editable, the save and close buttons will become visible (rather than light up, as is the case currently). Pressing ‘close’ will make the widget shrink back to the old state. The ‘old’ state could be either of scolling or stagnant lyrics. In the editable LyricsBrowser, the raw .lrc file (with timestamps) will be shown and saved. If a user replaces the timestamps (or creates an erroneous .lrc file), the LyricsBrowser will default to ‘stagnant lyrics’ state, and the timestamps, if any, will be stripped out from the display. The ‘scroll automatically’ button will now manage the ‘scrolling lyrics’ and ‘stagnant lyrics’ states. By toggling ‘scroll automatically’ a user can select to see the lyrics at his own pace i.e. the current behaviour with scrolling off. This won’t cause any expansion or shrinking of the height between the edit and display states. But in case of my new lyrics display widget will change size. If time permits, I can make the expansion and shrinking animated. The exact code to change the states will be contained in three public slots in the LyricsBrowser class: toScollingState(), toStagnantState(), toEditState(). The different properties will be defined (as it is now) in the LyricsBrowser class. The code to animate the transition, either added by me or by a future developer, can easily reside in these functions.</span></p>
</li></ul><p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt;margin-left:34.5pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">I will add two more buttons, just after the ‘edit lyrics’ button: ‘increase offset’ and ‘decrease offset’. They will be KIcon( “arrow-down” ) </span><img src="https://lh3.googleusercontent.com/Z9xLziu5UQb76Om-ufvLMJqZePzdOs2HY-wM_3OD-EN9Lk8BL2vI2Iqugv6VWrmK8tgBPWxUvgLAVjOTOLdY1-wYfEBhvVHVrtl4kahycICruXNFHfVjSSoxXVx-tg" width="27px;" height="20px;" style="border: none;"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">and KIcon( “arrow-up” ) </span><img src="https://lh6.googleusercontent.com/1o-5-x-Roi2mwrSvA1F1gWBxC7rrpEcJkpVcBVWxbcx5uzmhZrGDdf0BjyL6i4R5aPf7IEwU0YkeBU_Ei-eeF2isfCc2VS2U-_XnQUz837loR7CNqAjWtXUqWu_NWg" width="30px;" height="20px;" style="border: none;"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">respectively. They will be visible only in the ‘scrolling lyrics’ state. They will increase and decrease the offset of the current song lyrics by 500 milliseconds for each click. Offset is the value by which each timestamp in the .lrc file is adjusted when the lyrics is being displayed. When a user changes this offset, the .lrc file itself will be edited to persist these changes. If the offset value doesn’t exist in the .lrc file, it will be created.</span></p>
<ul style="margin-top:0pt;margin-bottom:0pt"><li dir="ltr" style="list-style-type:disc;font-size:13px;font-family:Arial;font-style:italic;vertical-align:baseline"><p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt">
<span style="color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">Animated Lyrics Scrolling:</span><span style="color:rgb(0,0,0);background-color:transparent;font-style:normal;vertical-align:baseline;white-space:pre-wrap"> After some research, I have decided I will implement scrolling just by listening to ‘The::engineController()->trackPositionChanged()’ signal. There is no need to set up any QPropertyAnimation or something more complex using QTimer. The ‘trackPositionChanged()’ signal sends a signal every couple of milliseconds as track progresses. I will set up key-value pairs according the timestamps given in the .lrc file and positions of the lines in our ‘browser’ object. I will store the QScrollBar returned by calling “browser->verticalScrollBar()” to ‘browserScrollBar’. A new KJob will parse the .lrc file into a QVector object (say ‘m_keyValues’) of ‘KeyValue’ (typdef for QPair<qreal,QVariant>) and different lines of lyrics that will go into the ‘browser’ object. Lets call this QVector ‘timestamps’. ‘keys’ will be the qreal quotient obtained by dividing the timestamp (in milliseconds) by total length of the song (also in milliseconds). ‘values’ will be integers representing the line number of the lyrics text. The integers will be the line numbers multiplied by ‘load’, where ‘load’ is the the length of song in milliseconds divided by 20. Hence, 1 integer value represents 20ms of the song. Updating the GUI every 20ms is ideal for smooth animation. Some ‘padding’ (i.e. blank) lines will be needed before the [00:00:00] timestamp line and after the last timestamped line in the .lrc file, so that the first and last lyric lines will appear at the centre rather than at the beginning or end of the widget. This is desirable since the centre line is only highlighted while the ends are not. The value of ‘padding’ will be calculated according to the size of the font selected by the user. It will be be the number of lines before (also, after) the centre line. The ‘values’ will be offset by INT_MIN. This is so that we can accommodate the maximum number of lines that ‘int’ can allow. Even that results to a maximum of ~21 minutes per song. (This would be a known issue that can be solved later by breaking the song into parts and loading those parts or decreasing the refresh rate to 50ms or even more.) We have to restrict ourselves to int (rather than quint64 or similar) since the ‘minimum’ and ‘maximum’ properties of QScrollBar are of ‘int’ type.</span></p>
</li></ul><p dir="ltr" style="line-height:1.15;margin-top:0pt;margin-bottom:0pt;margin-left:34.5pt"><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap">When this KJob is ‘finished()’, this QVector our song will be fully ready to be played with synchronized lyrics. All the operations (play, pause, seek) that a user (or other modules of Amarok or even KDE for that matter) will perform on the song playback can be easily reflected in the scrolling of the lyrics just by adding code to the LyricsBrowser::trackProgressed() slot. In this function, before QWidget::update() is called, ‘QAbstractSlider::setValue(int lineNo)’ will be emitted. ‘lineNo’ will be the value returned from an ‘int interpolate(qint64 position)’ function; it calculates the line number the lyrics should scroll to, based on current track ‘position’ and m_keyValues; calculation will be done according to linear interpolation of the closest earlier and later timestamps in m_keyValues. It will also account for the ‘offset’ value saved by the user when determining the line number to scroll to.</span><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);font-weight:bold;vertical-align:baseline;white-space:pre-wrap"></span></p>
<div><span style="font-size:13px;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><br></span></div></span></div></div>