OSDN Git Service

Some minor tweaks to the multi-threaded FileAnalyzer class.
[lamexp/LameXP.git] / src / Thread_FileAnalyzer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "Thread_FileAnalyzer.h"
23
24 #include "Global.h"
25 #include "LockedFile.h"
26 #include "Model_AudioFile.h"
27 #include "Thread_FileAnalyzer_Task.h"
28
29 #include <QDir>
30 #include <QFileInfo>
31 #include <QProcess>
32 #include <QDate>
33 #include <QTime>
34 #include <QDebug>
35 #include <QImage>
36 #include <QThreadPool>
37
38 ////////////////////////////////////////////////////////////
39 // Constructor
40 ////////////////////////////////////////////////////////////
41
42 FileAnalyzer::FileAnalyzer(const QStringList &inputFiles)
43 :
44         m_abortFlag(false),
45         m_inputFiles(inputFiles),
46         m_templateFile(NULL)
47 {
48         m_bSuccess = false;
49         m_bAborted = false;
50 }
51
52 FileAnalyzer::~FileAnalyzer(void)
53 {
54         if(m_templateFile)
55         {
56                 QString templatePath = m_templateFile->filePath();
57                 LAMEXP_DELETE(m_templateFile);
58                 if(QFile::exists(templatePath)) QFile::remove(templatePath);
59         }
60         
61         AnalyzeTask::reset();
62 }
63
64 ////////////////////////////////////////////////////////////
65 // Static data
66 ////////////////////////////////////////////////////////////
67
68 const char *FileAnalyzer::g_tags_gen[] =
69 {
70         "ID",
71         "Format",
72         "Format_Profile",
73         "Format_Version",
74         "Duration",
75         "Title", "Track",
76         "Track/Position",
77         "Artist", "Performer",
78         "Album",
79         "Genre",
80         "Released_Date", "Recorded_Date",
81         "Comment",
82         "Cover",
83         "Cover_Type",
84         "Cover_Mime",
85         "Cover_Data",
86         NULL
87 };
88
89 const char *FileAnalyzer::g_tags_aud[] =
90 {
91         "ID",
92         "Source",
93         "Format",
94         "Format_Profile",
95         "Format_Version",
96         "Channel(s)",
97         "SamplingRate",
98         "BitDepth",
99         "BitRate",
100         "BitRate_Mode",
101         NULL
102 };
103
104 ////////////////////////////////////////////////////////////
105 // Thread Main
106 ////////////////////////////////////////////////////////////
107
108 void FileAnalyzer::run()
109 {
110         m_bSuccess = false;
111         m_bAborted = false;
112
113         m_inputFiles.sort();
114         m_abortFlag = false;
115
116         if(!m_templateFile)
117         {
118                 if(!createTemplate())
119                 {
120                         qWarning("Failed to create template file!");
121                         return;
122                 }
123         }
124
125         AnalyzeTask::reset();
126         QThreadPool *pool = new QThreadPool();
127         
128         if(pool->maxThreadCount() < 2)
129         {
130                 pool->setMaxThreadCount(2);
131         }
132
133         while(!(m_inputFiles.isEmpty() || m_bAborted))
134         {
135                 while(!(m_inputFiles.isEmpty() || m_bAborted))
136                 {
137                         const QString currentFile = QDir::fromNativeSeparators(m_inputFiles.takeFirst());
138
139                         if(m_inputFiles.isEmpty())
140                         {
141                                 pool->waitForDone();
142                         }
143
144                         AnalyzeTask *task = new AnalyzeTask(currentFile, m_templateFile->filePath(), &m_abortFlag);
145                         connect(task, SIGNAL(fileSelected(QString)), this, SIGNAL(fileSelected(QString)), Qt::DirectConnection);
146                         connect(task, SIGNAL(fileAnalyzed(AudioFileModel)), this, SIGNAL(fileAnalyzed(AudioFileModel)), Qt::DirectConnection);
147
148                         while(!pool->tryStart(task))
149                         {
150                                 pool->waitForDone(250); //No more free threads, wait for active threads!
151                                 if(m_abortFlag) { LAMEXP_DELETE(task); break; }
152                         }
153
154                         if(m_abortFlag)
155                         {
156                                 MessageBeep(MB_ICONERROR);
157                                 m_bAborted = true;
158                         }
159
160                         QThread::yieldCurrentThread();
161                 }
162
163                 if(!m_bAborted)
164                 {
165                         pool->waitForDone();
166                         AnalyzeTask::getAdditionalFiles(m_inputFiles);
167                 }
168         }
169         
170         pool->waitForDone();
171         LAMEXP_DELETE(pool);
172         
173         if(m_bAborted)
174         {
175                 qWarning("Operation cancelled by user!");
176                 return;
177         }
178         
179         qDebug("All files added.\n");
180         m_bSuccess = true;
181 }
182
183 ////////////////////////////////////////////////////////////
184 // Privtae Functions
185 ////////////////////////////////////////////////////////////
186
187 bool FileAnalyzer::createTemplate(void)
188 {
189         if(m_templateFile)
190         {
191                 qWarning("Template file already exists!");
192                 return true;
193         }
194         
195         QString templatePath = QString("%1/%2.txt").arg(lamexp_temp_folder2(), lamexp_rand_str());
196
197         QFile templateFile(templatePath);
198         if(!templateFile.open(QIODevice::WriteOnly))
199         {
200                 return false;
201         }
202
203         templateFile.write("General;");
204         for(size_t i = 0; g_tags_gen[i]; i++)
205         {
206                 templateFile.write(QString("Gen_%1=%%1%\\n").arg(g_tags_gen[i]).toLatin1().constData());
207         }
208         templateFile.write("\\n\r\n");
209
210         templateFile.write("Audio;");
211         for(size_t i = 0; g_tags_aud[i]; i++)
212         {
213                 templateFile.write(QString("Aud_%1=%%1%\\n").arg(g_tags_aud[i]).toLatin1().constData());
214         }
215         templateFile.write("\\n\r\n");
216
217         bool success = (templateFile.error() == QFile::NoError);
218         templateFile.close();
219         
220         if(!success)
221         {
222                 QFile::remove(templatePath);
223                 return false;
224         }
225
226         try
227         {
228                 m_templateFile = new LockedFile(templatePath);
229         }
230         catch(...)
231         {
232                 qWarning("Failed to lock template file!");
233                 return false;
234         }
235
236         return true;
237 }
238
239 ////////////////////////////////////////////////////////////
240 // Public Functions
241 ////////////////////////////////////////////////////////////
242
243 unsigned int FileAnalyzer::filesAccepted(void)
244 {
245         return AnalyzeTask::filesAccepted();
246 }
247
248 unsigned int FileAnalyzer::filesRejected(void)
249 {
250         return AnalyzeTask::filesRejected();
251 }
252
253 unsigned int FileAnalyzer::filesDenied(void)
254 {
255         return AnalyzeTask::filesDenied();
256 }
257
258 unsigned int FileAnalyzer::filesDummyCDDA(void)
259 {
260         return AnalyzeTask::filesDummyCDDA();
261 }
262
263 unsigned int FileAnalyzer::filesCueSheet(void)
264 {
265         return AnalyzeTask::filesCueSheet();
266 }
267
268 ////////////////////////////////////////////////////////////
269 // EVENTS
270 ////////////////////////////////////////////////////////////
271
272 /*NONE*/