Skip to content

Commit

Permalink
Added an option to see the changes made in Editor in the test window …
Browse files Browse the repository at this point in the history
…in real-time, with optional seek backward for a specified number of seconds if the player is running. This allows easy fine-tuning of lyrics.
  • Loading branch information
gyunaev committed Dec 25, 2016
1 parent 0cb3128 commit 8c06c0e
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 20 deletions.
2 changes: 2 additions & 0 deletions Changelog
@@ -1,6 +1,8 @@
2016-12-24 gyunaev <gyunaev@ulduzsoft.com>
- Added support for importing KaraokeBuilder lyric files (thanks Ivan for providing examples).
- Switched to QAudioOutput instead of SDL, and thus got rid of SDL use.
- Added an option to see the changes made in Editor in the test window in real-time, with optional seek backward
for a specified number of seconds if the player is running. This allows easy fine-tuning of lyrics.

2016-12-23 gyunaev <gyunaev@ulduzsoft.com>
- Made "test lyrics" button reload lyrics without restarting the song (thx Dario Abatianni)
Expand Down
99 changes: 85 additions & 14 deletions src/dialog_settings.ui
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>574</width>
<height>351</height>
<width>566</width>
<height>362</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -111,17 +111,72 @@ p, li { white-space: pre-wrap; }
<property name="whatsThis">
<string>If blocks are enabled, this parameter specifies the maximum number of lines allowed in block. Most players cannot show more than 8 lines, so before using a larger parameter, please make sure your player supports it.</string>
</property>
<property name="suffix">
<string> lines</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>79</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QCheckBox" name="boxEditorRealtimeTesting">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;By default when you test the lyrics using &amp;quot;Test Lyrics&amp;quot; button, any change you made in the editor is ignored until you press the &amp;quot;Test Lyrics&amp;quot; button again. &lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;However if this option is checked, any change in the Editor, which happens while the Test Lyrics Window is shown and the song is playing, will automatically update and refresh the window. The player will also seek the specified number of seconds backward from the changed timing mark (unless set to 0 seconds), effectively letting you to see right away the result of your editing.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable realtime test window update; seek</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="leEditorSecondsBackward">
<property name="enabled">
<bool>false</bool>
</property>
<property name="whatsThis">
<string>If blocks are enabled, this parameter specifies the maximum number of lines allowed in block. Most players cannot show more than 8 lines, so before using a larger parameter, please make sure your player supports it.</string>
</property>
<property name="suffix">
<string> sec</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>lines</string>
<string>backward</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
Expand Down Expand Up @@ -726,8 +781,8 @@ p, li { white-space: pre-wrap; }
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>252</x>
<y>329</y>
<x>261</x>
<y>352</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
Expand All @@ -742,8 +797,8 @@ p, li { white-space: pre-wrap; }
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>320</x>
<y>329</y>
<x>329</x>
<y>352</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
Expand All @@ -758,12 +813,12 @@ p, li { white-space: pre-wrap; }
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>62</x>
<y>258</y>
<x>86</x>
<y>289</y>
</hint>
<hint type="destinationlabel">
<x>484</x>
<y>256</y>
<x>476</x>
<y>291</y>
</hint>
</hints>
</connection>
Expand All @@ -778,8 +833,24 @@ p, li { white-space: pre-wrap; }
<y>118</y>
</hint>
<hint type="destinationlabel">
<x>345</x>
<y>132</y>
<x>386</x>
<y>131</y>
</hint>
</hints>
</connection>
<connection>
<sender>boxEditorRealtimeTesting</sender>
<signal>toggled(bool)</signal>
<receiver>leEditorSecondsBackward</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>137</x>
<y>156</y>
</hint>
<hint type="destinationlabel">
<x>339</x>
<y>150</y>
</hint>
</hints>
</connection>
Expand Down
46 changes: 46 additions & 0 deletions src/editor.cpp
Expand Up @@ -76,6 +76,52 @@ void Editor::textModified()
return;

m_project->setModified();

// Validate the text silently; will use it later to show current status
QList<ValidatorError> errors;

validate( errors );

if ( !errors.isEmpty() )
{
pMainWindow->statusBar()->showMessage( tr("Lyric error: %1" ).arg( errors[0].error ));
return;
}

pMainWindow->statusBar()->showMessage( "" );

// Get the current line text
QString line = textCursor().block().text();

// And look up backward for a timing block divider
int timeend, timestart = textCursor().columnNumber();

// If we edit right before the time tag, this is relevant to prior time tag
if ( line[timestart] == '[' && timestart > 0 )
timestart--;

for ( ; timestart > 0; timestart-- )
if ( line[timestart] == '[' || line[timestart] == ']' )
break;

// If we found an open time tag [, this means the cursor is in time tag already.
// Find a closing tag
if ( line[timestart] == '[' )
timeend = line.indexOf( ']', timestart );
else
{
timeend = timestart;

for ( ; timestart > 0 && line[timestart] != '['; timestart-- )
;
}

// Couldn't happen, but just in case
if ( timeend == -1 || timestart == -1 || timestart >= timeend )
return;

QString prevtime = line.mid( timestart + 1, timeend - timestart - 1 );
emit lyricsChanged( timeToMark( prevtime ) );
}

QString Editor::exportToString()
Expand Down
3 changes: 3 additions & 0 deletions src/editor.h
Expand Up @@ -95,6 +95,9 @@ class Editor : public QTextEdit
bool importFromString( const QString& lyricstr );
bool importFromOldString( const QString& lyricstr );

signals:
void lyricsChanged( qint64 time );

public slots:
void textModified();
void splitLine();
Expand Down
27 changes: 26 additions & 1 deletion src/mainwindow.cpp
Expand Up @@ -201,6 +201,7 @@ void MainWindow::connectActions()
// Text editor
connect( actionUndo, SIGNAL( triggered()), editor, SLOT( undo()) );
connect( actionRedo, SIGNAL( triggered()), editor, SLOT( redo()) );
connect( editor, SIGNAL(lyricsChanged(qint64)), this, SLOT(lyricsChanged(qint64)) );

// Registration
connect( actionRegistration, SIGNAL( triggered()), this, SLOT( act_helpRegistration()) );
Expand Down Expand Up @@ -240,7 +241,31 @@ void MainWindow::editor_undoAvail(bool available)

void MainWindow::editor_redoAvail(bool available)
{
actionRedo->setEnabled( available );
actionRedo->setEnabled( available );
}

void MainWindow::lyricsChanged(qint64 time)
{
if ( !pSettings->m_editorAutoUpdateTestWindows )
return;

if ( m_testWindow )
{
Lyrics lyrics;

if ( !editor->exportLyrics( &lyrics ) )
return;

LyricsWidget * lw = new LyricsWidget( m_testWindow );
lw->setLyrics( lyrics,
m_project->tag( Project::Tag_Artist ),
m_project->tag( Project::Tag_Title ) );

m_testWindow->setLyricWidget( lw );

if ( m_player->isPlaying() && pSettings->m_editorAutoUpdatePlayerBackseek > 0 )
m_player->seekToTime( time - pSettings->m_editorAutoUpdatePlayerBackseek * 1000 );
}
}

void MainWindow::act_fileNewProject()
Expand Down
1 change: 1 addition & 0 deletions src/mainwindow.h
Expand Up @@ -44,6 +44,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindow
void updateState();
void editor_undoAvail(bool);
void editor_redoAvail(bool);
void lyricsChanged( qint64 time );

private slots:
void act_fileNewProject();
Expand Down
17 changes: 13 additions & 4 deletions src/playerwidget.cpp
Expand Up @@ -160,14 +160,23 @@ void PlayerWidget::btn_playerPlayPause()

void PlayerWidget::btn_playerSeekForward()
{
if ( pAudioPlayer->isPlaying() )
pAudioPlayer->seekTo( pAudioPlayer->currentTime() + 5000 );
seekToTime( pAudioPlayer->currentTime() + 5000 );
}

void PlayerWidget::btn_playerSeekBackward()
{
if ( pAudioPlayer->isPlaying() )
pAudioPlayer->seekTo( pAudioPlayer->currentTime() - 5000 );
seekToTime( pAudioPlayer->currentTime() - 5000 );
}

void PlayerWidget::seekToTime(qint64 time)
{
if ( pAudioPlayer->isPlaying() )
{
if ( time < 0 )
time = 0;

pAudioPlayer->seekTo( time );
}
}

void PlayerWidget::startPlaying()
Expand Down
1 change: 1 addition & 0 deletions src/playerwidget.h
Expand Up @@ -59,6 +59,7 @@ class PlayerWidget : public QDockWidget, public Ui::PlayerWidget
void btn_playerPlayPause();
void btn_playerSeekForward();
void btn_playerSeekBackward();
void seekToTime( qint64 time );

private slots:
void slotAudioTick( qint64 tickvalue );
Expand Down
12 changes: 11 additions & 1 deletion src/settings.cpp
Expand Up @@ -42,6 +42,8 @@ Settings::Settings()
m_editorFontFamily = settings.value( "editor/fontfamily", "arial" ).toString();
m_editorFontSize = settings.value( "editor/fontsize", 14 ).toInt();
m_editorDoubleTimeMark = settings.value( "editor/doubletimemark", true ).toBool();
m_editorAutoUpdateTestWindows = settings.value( "editor/autoupdatetestwindow", false ).toBool();
m_editorAutoUpdatePlayerBackseek = settings.value( "editor/autoupdateplayerbackseek", 0 ).toInt();

m_timeMarkFontFamily = settings.value( "timemark/fontfamily", "arial" ).toString();
m_timeMarkFontSize = settings.value( "timemark/fontsize", 10 ).toInt();
Expand Down Expand Up @@ -79,6 +81,9 @@ void Settings::edit()
ui.fontEditor->setCurrentFont( QFont( m_editorFontFamily ) );
ui.fontEditorSize->setValue( m_editorFontSize );

ui.boxEditorRealtimeTesting->setChecked( m_editorAutoUpdateTestWindows );
ui.leEditorSecondsBackward->setValue( m_editorAutoUpdatePlayerBackseek );

ui.fontTimeMark->setCurrentFont( QFont( m_timeMarkFontFamily ) );
ui.fontTimeMarkSize->setValue( m_timeMarkFontSize );
ui.btnTimingColorPhBg->setColor( m_timeMarkPlaceholderBackground );
Expand Down Expand Up @@ -108,7 +113,7 @@ void Settings::edit()
m_checkForUpdates = ui.cbCheckForUpdates->isChecked();

m_editorWordChars = ui.leEditorWordCount->text().toInt();
m_editorMaxBlock = ui.leEditorBlockLines->text().toInt();
m_editorMaxBlock = ui.leEditorBlockLines->value();

m_editorStopAtLineEnd = ui.cbEditorStopAtEnd->isChecked();
m_editorStopNextWord = ui.cbEditorStopAtWords->isChecked();
Expand All @@ -117,6 +122,9 @@ void Settings::edit()
m_editorFontFamily = ui.fontEditor->currentFont().family();
m_editorFontSize = ui.fontEditorSize->value();

m_editorAutoUpdateTestWindows = ui.boxEditorRealtimeTesting->isChecked();
m_editorAutoUpdatePlayerBackseek = ui.leEditorSecondsBackward->value();

m_timeMarkFontFamily = ui.fontTimeMark->currentFont().family();
m_timeMarkFontSize = ui.fontTimeMarkSize->value();
m_timeMarkPlaceholderBackground = ui.btnTimingColorPhBg->color();
Expand Down Expand Up @@ -145,6 +153,8 @@ void Settings::edit()
settings.setValue( "editor/fontfamily", m_editorFontFamily );
settings.setValue( "editor/fontsize", m_editorFontSize );
settings.setValue( "editor/doubletimemark", m_editorDoubleTimeMark );
settings.setValue( "editor/autoupdatetestwindow", m_editorAutoUpdateTestWindows );
settings.setValue( "editor/autoupdateplayerbackseek", m_editorAutoUpdatePlayerBackseek );

settings.setValue( "timemark/fontfamily", m_timeMarkFontFamily );
settings.setValue( "timemark/fontsize", m_timeMarkFontSize );
Expand Down
6 changes: 6 additions & 0 deletions src/settings.h
Expand Up @@ -65,6 +65,12 @@ class Settings
// at the same position.
bool m_editorDoubleTimeMark;

// If true, any change in the editor will automatically update the test window
// (if the test window is active). Also the player, if playing, will seek back
// m_editorAutoUpdatePlayerBackseek seconds if playing.
bool m_editorAutoUpdateTestWindows;
int m_editorAutoUpdatePlayerBackseek;

// Time mark font family and size
QString m_timeMarkFontFamily;
int m_timeMarkFontSize;
Expand Down

0 comments on commit 8c06c0e

Please sign in to comment.