1+ #include " LyricFAWindow.h"
2+
3+ #include < QApplication>
4+ #include < QFileDialog>
5+ #include < QLabel>
6+ #include < QLineEdit>
7+ #include < QMessageBox>
8+ #include < QStandardPaths>
9+
10+ #include " ../util/AsrThread.h"
11+ #include " ../util/FaTread.h"
12+
13+ namespace LyricFA {
14+
15+ LyricFAWindow::LyricFAWindow (QWidget *parent) : AsyncTaskWindow(parent) {
16+ const QString modelFolder = QDir::cleanPath (
17+ #ifdef Q_OS_MAC
18+ QApplication::applicationDirPath () + " /../Resources/model"
19+ #else
20+ QApplication::applicationDirPath () + QDir::separator () + " model"
21+ #endif
22+ );
23+ if (QDir (modelFolder).exists ()) {
24+ const auto modelPath = modelFolder + QDir::separator () + " model.onnx" ;
25+ const auto vocabPath = modelFolder + QDir::separator () + " vocab.txt" ;
26+ if (!QFile (modelPath).exists () || !QFile (vocabPath).exists ())
27+ QMessageBox::information (
28+ this , " Warning" ,
29+ " Missing model.onnx or vocab.txt, please read ReadMe.md and download the model again." );
30+ else
31+ m_asr = new Asr (modelFolder);
32+ } else {
33+ #ifdef Q_OS_MAC
34+ QMessageBox::information (
35+ this , " Warning" ,
36+ " Please read ReadMe.md and download asrModel to unzip to app bundle's Resources directory." );
37+ #else
38+ QMessageBox::information (this , " Warning" ,
39+ " Please read ReadMe.md and download asrModel to unzip to the root directory." );
40+ #endif
41+ }
42+
43+ m_mandarin = QSharedPointer<Pinyin::Pinyin>(new Pinyin::Pinyin ());
44+ m_match = new MatchLyric ();
45+
46+ setRunButtonText (" 运行 ASR" );
47+ LyricFAWindow::init ();
48+ }
49+
50+ LyricFAWindow::~LyricFAWindow () {
51+ delete m_asr;
52+ delete m_match;
53+ }
54+
55+ void LyricFAWindow::init () {
56+ auto *labLabel = new QLabel (" Lab Out Path:" , this );
57+ m_labEdit = new QLineEdit (R"( D:\python\LyricFA\test_outlab)" , this );
58+ auto *btnLab = new QPushButton (" Open Folder" , this );
59+ auto *labLayout = new QHBoxLayout ();
60+ labLayout->addWidget (m_labEdit);
61+ labLayout->addWidget (btnLab);
62+
63+ auto *jsonLabel = new QLabel (" Json Out Path:" , this );
64+ m_jsonEdit = new QLineEdit (R"( D:\python\LyricFA\test_outjson)" , this );
65+ auto *btnJson = new QPushButton (" Open Folder" , this );
66+ auto *jsonLayout = new QHBoxLayout ();
67+ jsonLayout->addWidget (m_jsonEdit);
68+ jsonLayout->addWidget (btnJson);
69+
70+ auto *lyricLabel = new QLabel (" Raw Lyric Path:" , this );
71+ m_lyricEdit = new QLineEdit (R"( D:\python\LyricFA\lyrics)" , this );
72+ auto *btnLyric = new QPushButton (" Lyric Folder" , this );
73+ auto *lyricLayout = new QHBoxLayout ();
74+ lyricLayout->addWidget (m_lyricEdit);
75+ lyricLayout->addWidget (btnLyric);
76+
77+ m_pinyinBox = new QCheckBox (" ASR result saved as pinyin" , this );
78+ m_matchBtn = new QPushButton (" 匹配歌词" , this );
79+ connect (m_matchBtn, &QPushButton::clicked, this , &LyricFAWindow::slot_matchLyric);
80+
81+ m_rightPanel->addWidget (labLabel);
82+ m_rightPanel->addLayout (labLayout);
83+ m_rightPanel->addWidget (jsonLabel);
84+ m_rightPanel->addLayout (jsonLayout);
85+ m_rightPanel->addWidget (lyricLabel);
86+ m_rightPanel->addLayout (lyricLayout);
87+ m_rightPanel->addWidget (m_pinyinBox);
88+ m_rightPanel->addWidget (m_matchBtn);
89+ m_rightPanel->addStretch ();
90+
91+ connect (btnLab, &QPushButton::clicked, this , &LyricFAWindow::slot_labPath);
92+ connect (btnJson, &QPushButton::clicked, this , &LyricFAWindow::slot_jsonPath);
93+ connect (btnLyric, &QPushButton::clicked, this , &LyricFAWindow::slot_lyricPath);
94+ }
95+
96+ void LyricFAWindow::runTask () {
97+ m_logOutput->clear ();
98+ m_threadPool->clear ();
99+
100+ const QString labOutPath = m_labEdit->text ();
101+ if (!QDir (labOutPath).exists ()) {
102+ QMessageBox::information (nullptr , " Warning" ,
103+ " Lab Out Path is empty or does not exist. Please set the output directory." );
104+ return ;
105+ }
106+
107+ m_totalTasks = taskList ()->count ();
108+ if (m_totalTasks == 0 ) {
109+ QMessageBox::information (this , " Info" , " No tasks to run." );
110+ return ;
111+ }
112+ m_finishedTasks = 0 ;
113+ m_errorTasks = 0 ;
114+ m_errorDetails.clear ();
115+ m_progressBar->setValue (0 );
116+ m_progressBar->setMaximum (m_totalTasks);
117+ m_currentMode = Mode_Asr;
118+
119+ const bool toPinyin = m_pinyinBox->isChecked ();
120+
121+ for (int i = 0 ; i < m_totalTasks; ++i) {
122+ const QListWidgetItem *item = taskList ()->item (i);
123+ QString filename = item->text ();
124+ const QString filePath = item->data (Qt::UserRole + 1 ).toString ();
125+ const QString labFilePath =
126+ labOutPath + QDir::separator () + QFileInfo (filename).completeBaseName () + " .lab" ;
127+
128+ auto *asrThread = new AsrThread (m_asr, filename, filePath, labFilePath,
129+ QSharedPointer<Pinyin::Pinyin>(toPinyin ? m_mandarin.data () : nullptr ));
130+ connect (asrThread, &AsrThread::oneFailed, this , &AsyncTaskWindow::slot_oneFailed);
131+ connect (asrThread, &AsrThread::oneFinished, this , &AsyncTaskWindow::slot_oneFinished);
132+ m_threadPool->start (asrThread);
133+ }
134+ }
135+
136+ void LyricFAWindow::onTaskFinished () {
137+ QString msg;
138+ if (m_currentMode == Mode_Asr) {
139+ msg = QString (" ASR 任务完成!总数: %3, 成功: %1, 失败: %2" )
140+ .arg (m_totalTasks - m_errorTasks)
141+ .arg (m_errorTasks)
142+ .arg (m_totalTasks);
143+ } else {
144+ msg = QString (" 歌词匹配完成!总数: %3, 成功: %1, 失败: %2" )
145+ .arg (m_totalTasks - m_errorTasks)
146+ .arg (m_errorTasks)
147+ .arg (m_totalTasks);
148+ }
149+
150+ if (m_errorTasks > 0 ) {
151+ m_logOutput->appendPlainText (" 失败任务列表:" );
152+ for (const QString &detail : m_errorDetails)
153+ m_logOutput->appendPlainText (" " + detail);
154+ m_errorDetails.clear ();
155+ }
156+
157+ QMessageBox::information (this , QApplication::applicationName (), msg);
158+ m_totalTasks = m_finishedTasks = m_errorTasks = 0 ;
159+ }
160+
161+ void LyricFAWindow::slot_matchLyric () {
162+ const QString lyricFolder = m_lyricEdit->text ();
163+ const QString labFolder = m_labEdit->text ();
164+ const QString jsonFolder = m_jsonEdit->text ();
165+
166+ if (!QDir (lyricFolder).exists () || !QDir (labFolder).exists () || !QDir (jsonFolder).exists ()) {
167+ QMessageBox::information (nullptr , " Warning" , " Please ensure all three paths exist and are set correctly." );
168+ return ;
169+ }
170+
171+ m_logOutput->clear ();
172+ m_threadPool->clear ();
173+
174+ QDir ().mkpath (jsonFolder);
175+
176+ const QDir labDir (labFolder);
177+ QStringList labPaths;
178+ for (const QString &file : labDir.entryList (QStringList () << " *.lab" , QDir::Files)) {
179+ labPaths << labDir.absoluteFilePath (file);
180+ }
181+
182+ if (labPaths.isEmpty ()) {
183+ QMessageBox::information (this , " Info" , " No .lab files found in the lab folder." );
184+ return ;
185+ }
186+
187+ m_match->initLyric (lyricFolder);
188+
189+ m_totalTasks = labPaths.size ();
190+ m_finishedTasks = 0 ;
191+ m_errorTasks = 0 ;
192+ m_errorDetails.clear ();
193+ m_progressBar->setValue (0 );
194+ m_progressBar->setMaximum (m_totalTasks);
195+ m_currentMode = Mode_MatchLyric;
196+
197+ for (const QString &labPath : labPaths) {
198+ QString labName = QFileInfo (labPath).completeBaseName ();
199+ const QString jsonPath = jsonFolder + QDir::separator () + labName + " .json" ;
200+
201+ auto *faThread = new FaTread (m_match, labName, labPath, jsonPath);
202+ connect (faThread, &FaTread::oneFailed, this , &AsyncTaskWindow::slot_oneFailed);
203+ connect (faThread, &FaTread::oneFinished, this , &AsyncTaskWindow::slot_oneFinished);
204+ m_threadPool->start (faThread);
205+ }
206+ }
207+
208+ void LyricFAWindow::slot_labPath () {
209+ const QString path = QFileDialog::getExistingDirectory (
210+ this , " Select Lab Output Directory" , QStandardPaths::writableLocation (QStandardPaths::DesktopLocation));
211+ if (!path.isEmpty ())
212+ m_labEdit->setText (path);
213+ }
214+
215+ void LyricFAWindow::slot_jsonPath () {
216+ const QString path = QFileDialog::getExistingDirectory (
217+ this , " Select Json Output Directory" , QStandardPaths::writableLocation (QStandardPaths::DesktopLocation));
218+ if (!path.isEmpty ())
219+ m_jsonEdit->setText (path);
220+ }
221+
222+ void LyricFAWindow::slot_lyricPath () {
223+ const QString path = QFileDialog::getExistingDirectory (
224+ this , " Select Raw Lyric Directory" , QStandardPaths::writableLocation (QStandardPaths::DesktopLocation));
225+ if (!path.isEmpty ())
226+ m_lyricEdit->setText (path);
227+ }
228+
229+ } // namespace LyricFA
0 commit comments